home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / 9901.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  12.2 KB  |  482 lines

  1.  
  2. /*    CRU module for 9901 I/O controller. */
  3.  
  4. #include "v9t9_common.h"
  5. #include "v9t9.h"
  6. #include "roms.h"
  7. #include "cru.h"
  8. #include "9900.h"
  9.  
  10. #include "keyboard.h"
  11. #include "emulate.h"
  12. #include "sound.h"
  13. #include "vdp.h"
  14. #include "timer.h"
  15.  
  16. #define _L     LOG_CRU | LOG_INFO
  17.  
  18. hw9901state hw9901;
  19. AudioGate audiogate;
  20.  
  21. /***************************************************/
  22.  
  23. void        
  24. reset9901()
  25. {
  26.     memset(crukeyboardmap, 0, sizeof(crukeyboardmap));
  27.     memset((void *)&hw9901, 0, sizeof(hw9901));
  28. }
  29.  
  30. /*
  31.     handle9901() is called when something about the 
  32.     interrupt state changes (processor interrupt mask,
  33.     pending interrupt mask, etc).  If an interrupt is needed,
  34.     this triggers the INTPIN_INTREQ pin on the 9900, and sets the 
  35.     ST_INTERRUPT flag in stateflag.
  36. */
  37. static void
  38. handle9901(void)
  39. {
  40.     // any of these interrupts enabled?  [optimization]
  41.     if (hw9901.currentints & hw9901.int9901) {
  42.         // There are 16 levels, and intlevel is 16 bits.
  43.         // When it goes from 0x8000 to 0, we will see there
  44.         // are no interrupts that can be passed.
  45.         hw9901.intlevel = M_INT_EXT;
  46.         while (hw9901.intlevel && ((hw9901.currentints & hw9901.int9901) & hw9901.intlevel) == 0)
  47.             hw9901.intlevel =
  48.                 (hw9901.intlevel << 1) & (M_INT_EXT | M_INT_VDP | M_INT_CLOCK);
  49.  
  50.         if (hw9901.intlevel) {
  51.             logger(_L | L_1, "Triggering interrupt... %04X/%04X/%04X\n", hw9901.intlevel,
  52.                  hw9901.currentints, hw9901.int9901);
  53.  
  54.             intpins9900 |= INTPIN_INTREQ;
  55.             stateflag |= ST_INTERRUPT;
  56.         }
  57.     }
  58. }
  59.  
  60. /*
  61.     Trigger an interrupt, via hardware.
  62. */
  63. void
  64. trigger9901int(u16 mask)
  65. {
  66.     if (hw9901.int9901 & mask) {
  67.         hw9901.currentints |= mask;
  68.  
  69.         // see if it applies
  70.         handle9901();
  71.     }
  72. }
  73.  
  74.  
  75. /*
  76.     Reset an interrupt, via hardware.
  77. */
  78. void
  79. reset9901int(u16 mask)
  80. {
  81.     if (hw9901.currentints & mask) {
  82.         hw9901.currentints &= ~mask;
  83.  
  84.         // take care of pending interrupts
  85.         handle9901();
  86.     }
  87. }
  88.  
  89. u16 read9901int(void)
  90. {
  91.     return hw9901.intlevel;
  92. }
  93.  
  94. /***************************************************/
  95.  
  96. static int clock9901tag;
  97.  
  98. // if TM_HZ < 46875, we must pretend
  99. // to have skipped this many clicks
  100. // for every call to clock_9901_event().
  101. static    u32  clockdelta;
  102.  
  103. static void
  104. clock_9901_event(int tag)
  105. {
  106.     logger(_L | L_2, "**** clock_9901_event %d/%d ****\n", hw9901.timer, clockdelta);
  107.     // '<' prevents timer interrupts
  108.     // when clockinvl (thus clockdelta) is zero
  109.     if (hw9901.timer < clockdelta) {
  110.         trigger9901int(M_INT_CLOCK);
  111.  
  112.         // if resolution is too low, at least
  113.         // keep the wavelength the same
  114.         if (hw9901.clockinvl < clockdelta)
  115.             hw9901.timer += clockdelta + hw9901.clockinvl;
  116.         else
  117.             hw9901.timer += hw9901.clockinvl;
  118.     }
  119.  
  120.     hw9901.timer -= clockdelta;
  121. }
  122.  
  123. /*
  124.  *    Called from emulate() to mark time.
  125.  */
  126. void
  127. handle9901tick(void)
  128. {
  129.     if (!hw9901.clockmode && hw9901.clockinvl && hw9901.timer-- == 0) {
  130.         logger(_L | L_2, "**** handle9901tick ****");
  131.         trigger9901int(M_INT_CLOCK);
  132.         hw9901.timer = hw9901.clockinvl;
  133.  
  134.     }
  135. }
  136.  
  137. void
  138. setclockmode9901(u8 onoff)
  139. {
  140.     // SBO 0 turns on clock mode, SBZ 0 turns on I/O mode
  141.     if (!onoff) {
  142.         // set new speed
  143.         hw9901.clockinvl = hw9901.latchedclockinvl;
  144.         hw9901.timer = hw9901.clockinvl;
  145.  
  146. //      TM_ResetEvent(clock9901tag);
  147.         if (hw9901.clockinvl) {
  148.             logger(_L | 0, "*** Setting clock to %5.2f Hz\n\n",
  149.                  3000000.0 / 64 / hw9901.clockinvl);
  150. //          #warning main clock hertz
  151. //          clockdelta = 3000000 / 64 / TM_HZ;
  152. //          TM_SetEvent(clock9901tag, TM_HZ * 100 / 100, 0, 
  153. //                      TM_FUNC|TM_REPEAT, clock_9901_event);
  154.         } else {
  155. //          clockdelta = 0;
  156.         }
  157.  
  158.         hw9901.clockmode = 0;
  159.     } else {
  160.         // setting clock mode freezes read register
  161.         // (not to mention allowing access to the read register!)
  162.         // but the decrementer continues    
  163.  
  164.         if (hw9901.clockinvl)
  165.             hw9901.latchedtimer = hw9901.timer % hw9901.clockinvl;
  166.         else
  167.             hw9901.latchedtimer = 0;
  168.  
  169.         hw9901.clockmode = 1;
  170.     }
  171. }
  172.  
  173. /******************************************************/
  174.  
  175. static      u32
  176. crur9901_0(u32 addr, u32 data, u32 num)
  177. {
  178.     return 1;
  179. }
  180.  
  181. /*    Read INT_EXT status or lowest bit of timer.  */
  182. static      u32
  183. crur9901_1(u32 addr, u32 data, u32 num)
  184. {
  185.     if (hw9901.clockmode)
  186.         return (hw9901.latchedtimer & 1);
  187.     else if (hw9901.int9901 & M_INT_EXT) {
  188.         logger(_L | L_1, "crur9901_1: currentints=%04X\n", hw9901.currentints);
  189.         return !(hw9901.currentints & M_INT_EXT);
  190.     } else
  191.         return 0;
  192. }
  193.  
  194. /*    Read INT_VDP status or 2nd bit of timer.  
  195.     Don't return INT_VDP status if INT1 is still waiting.
  196. */
  197. static      u32
  198. crur9901_2(u32 addr, u32 data, u32 num)
  199. {
  200.     if (hw9901.clockmode)
  201.         return (hw9901.latchedtimer >> 1) & 1;
  202.     else if (hw9901.int9901 & M_INT_VDP) {
  203.         logger(_L | L_1, "crur9901_2: currentints=%04X\n", hw9901.currentints);
  204.         //return !(hw9901.currentints&M_INT_EXT) && !!(hw9901.currentints & M_INT_VDP);
  205.         return !(hw9901.currentints & M_INT_VDP);
  206.     } else
  207.         return 0;
  208. }
  209.  
  210. static      u32
  211. crur9901_LS(u32 addr, u32 data, u32 num)
  212. {
  213.     return (hw9901.clockmode ? 0 : 1);
  214. }
  215.  
  216. /*    Note:  the keyboard module is only allowed to
  217.     set the crukeyboardmap[], not take over the I/O for it. */
  218.  
  219. static      u32
  220. crur9901_KS(u32 addr, u32 data, u32 num)
  221. {
  222.     int         mask;
  223.     u32         bit = addr / 2;
  224.  
  225.     mask = 1 << (bit - 3);
  226.  
  227.     if (hw9901.clockmode)
  228.         return (hw9901.latchedtimer >> (bit - 1)) & 0x1;
  229.     else if (hw9901.int9901 & (1 << bit))
  230.         return !(hw9901.currentints & ~(~0 << bit)) && !!(hw9901.currentints & (1 << bit));
  231.     else {
  232.         u32         alphamask =
  233.             ((bit - 3) == 4) ? ((AlphaLock || !caps) ? 0 : 0x10) : 0;
  234.  
  235.         logger(_L | L_2, "crukeyboardcol=%X, mask=%X, addr=%2X\n", crukeyboardcol,
  236.              mask, addr);
  237.         return !(((crukeyboardmap[crukeyboardcol] & mask) | alphamask));
  238.     }
  239. }
  240.  
  241. static      u32
  242. cruralpha(u32 addr, u32 data, u32 num)
  243. {
  244.     return caps & 1;
  245.  
  246. }
  247.  
  248. static      u32
  249. crurCSIn(u32 addr, u32 data, u32 num)
  250. {
  251.     return cassette_read();
  252. }
  253.  
  254. /**********************************************/
  255.  
  256. static      u32
  257. cruw9901_0(u32 addr, u32 data, u32 num)
  258. {
  259.     setclockmode9901(data);
  260.     return 0;
  261. }
  262.  
  263. /*
  264.     Change an interrupt enable, or change bit in clock interval
  265. */
  266. static      u32
  267. cruw9901_S(u32 addr, u32 data, u32 num)
  268. {
  269.     u32         bit = addr / 2;
  270.  
  271.     if (hw9901.clockmode) {
  272.         hw9901.latchedclockinvl =
  273.             (hw9901.latchedclockinvl & ~(1 << bit)) | (data << bit);
  274.         logger(_L | L_2, "cruw9901_S:  hw9901.latchedclockinvl=%04X\n",
  275.              hw9901.latchedclockinvl);
  276.     } else {
  277.         u32         mask = (~((~0) << num)) << bit;
  278.  
  279. /*        if (addr == 0x1a) {
  280.             cruwAudioGate(addr, data, num);
  281.             return;
  282.         } else if (addr == 0x1c) {
  283.             cruwCS2Motor(addr, data, num);
  284.             return;
  285.         }*/
  286.  
  287.         logger(_L | L_2, "Altering 9901 bit... addr=%04X, data=%04X,mask=%04X\n", addr,
  288.              data, mask);
  289.  
  290.         //  First, writing a 0 will disable the interrupt,
  291.         //  and writing a 1 will enable it, or acknowledge it.
  292.         hw9901.int9901 = (hw9901.int9901 & ~mask) | (data << bit);
  293.         logger(_L | L_2, "before reset: int9901 = %04X, currentints = %04X\n", hw9901.int9901,
  294.              hw9901.currentints);
  295.  
  296.         //  This will acknowledge the interrupt, and possibly
  297.         //  trigger a lower-level pending interrupt.
  298.         reset9901int(data << bit);
  299.         logger(_L | L_2, "after reset: int9901 = %04X, currentints = %04X\n", hw9901.int9901,
  300.              hw9901.currentints);
  301.  
  302. //      if (bit == 3)
  303. //          if (data) debugger_enable(); else debugger_disable();
  304.  
  305.         /*  int9901change();
  306.            handle9901(); */
  307.     }
  308.     return 0;
  309. }
  310.  
  311. static      u32
  312. cruwCS1Motor(u32 addr, u32 data, u32 num)
  313. {
  314.     cassette_set_motor(0, data);
  315.     return 0;
  316. }
  317.  
  318. static      u32
  319. cruwCS2Motor(u32 addr, u32 data, u32 num)
  320. {
  321.     cassette_set_motor(1, data);
  322.     return 0;
  323. }
  324.  
  325. /*    Enable/disable audio gate */
  326. static      u32
  327. cruwAudioGate(u32 addr, u32 data, u32 num)
  328. {
  329.     audiogate.play = data;
  330.     logger(_L | L_2, "audiogate.play=%d\n", data);
  331.     return 0;
  332. }
  333.  
  334. /*    Send bit to cassette  */
  335. static      u32
  336. cruwCSOut(u32 addr, u32 data, u32 num)
  337. {
  338.     /*  purposefully avoid gathering more than 1/100 second
  339.        of info at a time */
  340.     if (audiogate.latch != data || currenttime < audiogate.base_time)    // "a lot of" time passed
  341.     {
  342.         audiogate.latch = data;
  343.         audiogate.hertz = baseclockhz / 64 / BASE_EMULATOR_HZ;
  344.  
  345.         logger(_L | L_2, "currenttime=%d, base_time=%d\n", currenttime,
  346.              audiogate.base_time);
  347.  
  348.         audiogate.length = currenttime - audiogate.base_time;
  349.         if (currenttime < audiogate.base_time) {
  350.             // flush buffer -- we will generate data too fast to play it!
  351.             //SOUNDPLAY(vms_AG, NULL, 0, 0);
  352.             audiogate.length += audiogate.hertz;
  353.         }
  354.  
  355.         /*  write to "cassette"... */
  356.         cassette_write(audiogate.length, baseclockhz / 64);
  357.  
  358.         /*  also play  */
  359.         SOUNDPLAY(vms_AGw, NULL, audiogate.length, baseclockhz / 64);
  360.  
  361.         audiogate.base_time = currenttime;
  362.     }
  363.  
  364.     audiogate.last_time = currenttime;
  365.     return 0;
  366. }
  367.  
  368. /***********************************************/
  369.  
  370. /*    Note:  the keyboard module is only allowed to
  371.     set the crukeyboardmap[], not take over the I/O for it. */
  372.  
  373. static      u32
  374. cruwkeyboard_0(u32 addr, u32 data, u32 num)
  375. {
  376.     crukeyboardcol = (crukeyboardcol & 3) | (data << 2);
  377.     return 0;
  378. }
  379.  
  380. static      u32
  381. cruwkeyboard_1(u32 addr, u32 data, u32 num)
  382. {
  383.     crukeyboardcol = (crukeyboardcol & 5) | (data << 1);
  384.     return 0;
  385. }
  386.  
  387. static      u32
  388. cruwkeyboard_2(u32 addr, u32 data, u32 num)
  389. {
  390.     crukeyboardcol = (crukeyboardcol & 6) | (data);
  391.     return 0;
  392. }
  393.  
  394. static      u32
  395. cruwAlpha(u32 addr, u32 data, u32 num)
  396. {
  397.     AlphaLock = data;
  398.     return 0;
  399. }
  400.  
  401. /*****************************************/
  402.  
  403. int
  404. setup_9901(void)
  405. {
  406.     clock9901tag = TM_UniqueTag();
  407.  
  408.     if (cruadddevice(CRU_WRITE, 0x0, 1, cruw9901_0) &&
  409.         cruadddevice(CRU_WRITE, 0x2, 1, cruw9901_S) &&
  410.         cruadddevice(CRU_WRITE, 0x4, 1, cruw9901_S) &&
  411.         cruadddevice(CRU_WRITE, 0x6, 1, cruw9901_S) &&
  412.         cruadddevice(CRU_WRITE, 0x8, 1, cruw9901_S) &&
  413.         cruadddevice(CRU_WRITE, 0xa, 1, cruw9901_S) &&
  414.         cruadddevice(CRU_WRITE, 0xc, 1, cruw9901_S) &&
  415.         cruadddevice(CRU_WRITE, 0xe, 1, cruw9901_S) &&
  416.         cruadddevice(CRU_WRITE, 0x10, 1, cruw9901_S) &&
  417.         cruadddevice(CRU_WRITE, 0x12, 1, cruw9901_S) &&
  418.         cruadddevice(CRU_WRITE, 0x14, 1, cruw9901_S) &&
  419.         cruadddevice(CRU_WRITE, 0x16, 1, cruw9901_S) &&
  420.         cruadddevice(CRU_WRITE, 0x18, 1, cruw9901_S) &&
  421.         cruadddevice(CRU_WRITE, 0x1a, 1, cruw9901_S) &&
  422.         cruadddevice(CRU_WRITE, 0x1c, 1, cruw9901_S) &&
  423. //      cruadddevice(CRU_WRITE,0x1a,1,cruwAudioGate) &&     // primary use as timer bit
  424. //      cruadddevice(CRU_WRITE,0x1c,1,cruwCS2Motor) &&      // primary use as timer bit
  425. //      cruadddevice(CRU_WRITE,0x1e,1,cruwCS1Motor) &&
  426.         cruadddevice(CRU_WRITE, 0x24, 1, cruwkeyboard_2) &&
  427.         cruadddevice(CRU_WRITE, 0x26, 1, cruwkeyboard_1) &&
  428.         cruadddevice(CRU_WRITE, 0x28, 1, cruwkeyboard_0) &&
  429.         cruadddevice(CRU_WRITE, 0x2A, 1, cruwAlpha) &&
  430.         cruadddevice(CRU_WRITE, 0x2c, 1, cruwCS1Motor) &&
  431.         cruadddevice(CRU_WRITE, 0x2e, 1, cruwCS2Motor) &&
  432.         cruadddevice(CRU_WRITE, 0x30, 1, cruwAudioGate) &&
  433.         cruadddevice(CRU_WRITE, 0x32, 1, cruwCSOut) &&
  434.         cruadddevice(CRU_READ, 0x0, 1, crur9901_0) &&
  435.         cruadddevice(CRU_READ, 0x2, 1, crur9901_1) &&
  436.         cruadddevice(CRU_READ, 0x4, 1, crur9901_2) &&
  437.         cruadddevice(CRU_READ, 0x6, 1, crur9901_KS) &&
  438.         cruadddevice(CRU_READ, 0x8, 1, crur9901_KS) &&
  439.         cruadddevice(CRU_READ, 0xa, 1, crur9901_KS) &&
  440.         cruadddevice(CRU_READ, 0xc, 1, crur9901_KS) &&
  441.         cruadddevice(CRU_READ, 0xe, 1, crur9901_KS) &&
  442.         cruadddevice(CRU_READ, 0x10, 1, crur9901_KS) &&
  443.         cruadddevice(CRU_READ, 0x12, 1, crur9901_KS) &&
  444.         cruadddevice(CRU_READ, 0x14, 1, crur9901_KS) &&
  445.         cruadddevice(CRU_READ, 0x18, 1, crur9901_LS) &&    // "Pull up 10K to +5V"
  446. //      cruadddevice(CRU_READ,0x1a,1,crur9901_LS) &&    // output only
  447. //      cruadddevice(CRU_READ,0x1c,1,crur9901_LS) &&    // output only
  448. //      cruadddevice(CRU_READ,0x1e,1,crur9901_LS) &&    // output only
  449.         cruadddevice(CRU_READ, 0x20, 1, crur9901_LS) &&    // not connected
  450.         cruadddevice(CRU_READ, 0x22, 1, crur9901_LS) &&    // not connected
  451.         cruadddevice(CRU_READ, 0x2a, 1, cruralpha) &&
  452.         cruadddevice(CRU_READ, 0x36, 1, crurCSIn)) {
  453.         return 1;
  454.     } else
  455.         return 0;
  456. }
  457.  
  458. DECL_SYMBOL_ACTION(hw9901_machine_state)
  459. {
  460.     char *str;
  461.     if (task == csa_READ) {
  462.         char tmp[(sizeof(hw9901)+sizeof(audiogate))*2+1];
  463.  
  464.         if (iter)
  465.             return 0;
  466.  
  467.         emulate_bin2hex((u8 *)&hw9901, tmp, sizeof(hw9901));
  468.         command_arg_set_string(sym->args, tmp);
  469.         emulate_bin2hex((u8 *)&audiogate, tmp, sizeof(audiogate));
  470.         command_arg_set_string(sym->args->next, tmp);
  471.         
  472.         return 1;
  473.     }
  474.     command_arg_get_string(sym->args, &str);
  475.     emulate_hex2bin(str, (u8 *)&hw9901, sizeof(hw9901));
  476.     command_arg_get_string(sym->args->next, &str);
  477.     emulate_hex2bin(str, (u8 *)&audiogate, sizeof(audiogate));
  478.  
  479.     setclockmode9901(hw9901.clockmode);
  480.     return 1;
  481. }
  482.