AliM1543C.cpp

Go to the documentation of this file.
00001 /* ES40 emulator.
00002  * Copyright (C) 2007-2008 by the ES40 Emulator Project
00003  *
00004  * Website: http://sourceforge.net/projects/es40
00005  * E-mail : camiel@camicom.com
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020  * 
00021  * Although this is not required, the author would appreciate being notified of, 
00022  * and receiving any modifications you may make to the source code that might serve
00023  * the general public.
00024  */
00025 
00262 #include "StdAfx.h"
00263 #include "AliM1543C.h"
00264 #include "System.h"
00265 #include "VGA.h"
00266 
00267 #ifdef DEBUG_PIC
00268 bool  pic_messages = false;
00269 #endif
00270 
00271 /* Timer Calibration: Instructions per Microsecond (assuming 1 clock = 1 instruction) */
00272 #define IPus  847
00273 
00274 u32   ali_cfg_data[64] = {
00275   /*00*/ 0x153310b9,  // CFID: vendor + device
00276   /*04*/ 0x0200000f,  // CFCS: command + status
00277   /*08*/ 0x060100c3,  // CFRV: class + revision
00278   /*0c*/ 0x00000000,  // CFLT: latency timer + cache line size
00279   /*10*/ 0x00000000,  // BAR0:
00280   /*14*/ 0x00000000,  // BAR1:
00281   /*18*/ 0x00000000,  // BAR2:
00282   /*1c*/ 0x00000000,  // BAR3:
00283   /*20*/ 0x00000000,  // BAR4:
00284   /*24*/ 0x00000000,  // BAR5:
00285   /*28*/ 0x00000000,  // CCIC: CardBus
00286   /*2c*/ 0x00000000,  // CSID: subsystem + vendor
00287   /*30*/ 0x00000000,  // BAR6: expansion rom base
00288   /*34*/ 0x00000000,  // CCAP: capabilities pointer
00289   /*38*/ 0x00000000,
00290   /*3c*/ 0x00000000,  // CFIT: interrupt configuration
00291   0, 0, 0, 0, 0,
00292   /*54*/ 0x00000200,  //
00293   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00294   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00295   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00296 };
00297 
00298 u32   ali_cfg_mask[64] = {
00299   /*00*/ 0x00000000,  // CFID: vendor + device
00300   /*04*/ 0x00000000,  // CFCS: command + status
00301   /*08*/ 0x00000000,  // CFRV: class + revision
00302   /*0c*/ 0x00000000,  // CFLT: latency timer + cache line size
00303   /*10*/ 0x00000000,  // BAR0
00304   /*14*/ 0x00000000,  // BAR1: CBMA
00305   /*18*/ 0x00000000,  // BAR2:
00306   /*1c*/ 0x00000000,  // BAR3:
00307   /*20*/ 0x00000000,  // BAR4:
00308   /*24*/ 0x00000000,  // BAR5:
00309   /*28*/ 0x00000000,  // CCIC: CardBus
00310   /*2c*/ 0x00000000,  // CSID: subsystem + vendor
00311   /*30*/ 0x00000000,  // BAR6: expansion rom base
00312   /*34*/ 0x00000000,  // CCAP: capabilities pointer
00313   /*38*/ 0x00000000,
00314   /*3c*/ 0x00000000,  // CFIT: interrupt configuration
00315   /*40*/ 0xffcfff7f,
00316   /*44*/ 0xff00cbdf,
00317   /*48*/ 0xffffffff,
00318   /*4c*/ 0x000000ff,
00319   /*50*/ 0xffff8fff,
00320   /*54*/ 0xf0ffff00,
00321   /*58*/ 0x030f0d7f,
00322   0, 0, 0, 0, 0, 0, 0, 0, 0,
00323   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00324   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00325 };
00326 
00330 CAliM1543C::CAliM1543C(CConfigurator* cfg, CSystem* c, int pcibus, int pcidev) : CPCIDevice(cfg, c, pcibus, pcidev)
00331 {
00332   if(theAli != 0)
00333     FAILURE(Configuration, "More than one Ali");
00334   theAli = this;
00335 }
00336 
00340 void CAliM1543C::init()
00341 {
00342   add_function(0, ali_cfg_data, ali_cfg_mask);
00343 
00344   int     i;
00345   char*   filename;
00346 
00347   add_legacy_io(1, 0x61, 1);
00348 
00349   state.reg_61 = 0;
00350 
00351   add_legacy_io(2, 0x70, 4);
00352   cSystem->RegisterMemory(this, 2, U64(0x00000801fc000070), 4);
00353   for(i = 0; i < 4; i++)
00354     state.toy_access_ports[i] = 0;
00355   for(i = 0; i < 256; i++)
00356     state.toy_stored_data[i] = 0;
00357 
00358   state.toy_stored_data[0x17] = myCfg->get_bool_value("vga_console") ? 1 : 0;
00359 
00360   if(state.toy_stored_data[0x17] && !theVGA)
00361   {
00362     printf("! CONFIGURATION WARNING ! vga_console set to true, but no VGA card installed.\n");
00363     state.toy_stored_data[0x17] = 0;
00364   }
00365 
00366   ResetPCI();
00367 
00368   // PIT Setup
00369   add_legacy_io(6, 0x40, 4);
00370   for(i = 0; i < 3; i++)
00371     state.pit_status[i] = 0x40; // invalid/null counter
00372   for(i = 0; i < 9; i++)
00373     state.pit_counter[i] = 0;
00374 
00375   add_legacy_io(7, 0x20, 2);
00376   add_legacy_io(8, 0xa0, 2);
00377   add_legacy_io(30, 0x4d0, 2);
00378 
00379   // odd one, byte read in PCI IACK (interrupt acknowledge) cycle. Interrupt vector.
00380   cSystem->RegisterMemory(this, 20, U64(0x00000801f8000000), 1);
00381 
00382   for(i = 0; i < 2; i++)
00383   {
00384     state.pic_mode[i] = 0;
00385     state.pic_intvec[i] = 0;
00386     state.pic_mask[i] = 0;
00387     state.pic_asserted[i] = 0;
00388   }
00389 
00390   // Initialize parallel port
00391   add_legacy_io(27, 0x3bc, 4);
00392   filename = myCfg->get_text_value("lpt.outfile");
00393   if(filename)
00394   {
00395     lpt = fopen(filename, "ab");
00396   }
00397   else
00398   {
00399     lpt = NULL;
00400   }
00401 
00402   lpt_reset();
00403 
00404   myRegLock = new CMutex("ali-reg");
00405 
00406   myThread = 0;
00407 
00408   printf("%s: $Id: AliM1543C.cpp,v 1.65 2008/03/14 15:30:50 iamcamiel Exp $\n",
00409          devid_string);
00410 }
00411 
00412 void CAliM1543C::start_threads()
00413 {
00414   if(!myThread)
00415   {
00416     myThread = new Poco::Thread("ali");
00417     printf(" %s", myThread->getName().c_str());
00418     StopThread = false;
00419     myThread->start(*this);
00420   }
00421 }
00422 
00423 void CAliM1543C::stop_threads()
00424 {
00425   StopThread = true;
00426   if(myThread)
00427   {
00428     printf(" %s", myThread->getName().c_str());
00429     myThread->join();
00430     delete myThread;
00431     myThread = 0;
00432   }
00433 }
00434 
00438 CAliM1543C::~CAliM1543C()
00439 {
00440   stop_threads();
00441 
00442   if(lpt)
00443     fclose(lpt);
00444 }
00445 
00460 u32 CAliM1543C::ReadMem_Legacy(int index, u32 address, int dsize)
00461 {
00462   if(dsize != 8 && index != 20) // when interrupt vector is read, dsize doesn't matter.
00463   {
00464     FAILURE_4(InvalidArgument,
00465               "%s: DSize %d reading from legacy memory range # %d at address %02x\n",
00466               devid_string, dsize, index, address);
00467   }
00468 
00469   int channel = 0;
00470   switch(index)
00471   {
00472   case 1:   return reg_61_read();
00473   case 2:   return toy_read(address);
00474   case 6:   return pit_read(address);
00475   case 8:   channel = 1;
00476   case 7:   return pic_read(channel, address);
00477   case 20:  return pic_read_vector();
00478   case 30:  return pic_read_edge_level(address);
00479   case 27:  return lpt_read(address);
00480   }
00481 
00482   return 0;
00483 }
00484 
00503 void CAliM1543C::WriteMem_Legacy(int index, u32 address, int dsize, u32 data)
00504 {
00505   if(dsize != 8)
00506   {
00507     FAILURE_4(InvalidArgument,
00508               "%s: DSize %d writing to legacy memory range # %d at address %02x\n",
00509               devid_string, dsize, index, address);
00510   }
00511 
00512   int channel = 0;
00513   switch(index)
00514   {
00515   case 1:   reg_61_write((u8) data); return;
00516   case 2:   toy_write(address, (u8) data); return;
00517   case 6:   pit_write(address, (u8) data); return;
00518   case 8:   channel = 1;
00519   case 7:   pic_write(channel, address, (u8) data); return;
00520   case 30:  pic_write_edge_level(address, (u8) data); return;
00521   case 27:  lpt_write(address, (u8) data); return;
00522   }
00523 }
00524 
00539 u8 CAliM1543C::reg_61_read()
00540 {
00541 #if 0
00542   static long read_count = 0;
00543   if(!(state.reg_61 & 0x20))
00544   {
00545     if(read_count % 1500 == 0)
00546       state.reg_61 |= 0x20;
00547   }
00548   else
00549   {
00550     state.reg_61 &= ~0x20;
00551   }
00552 
00553   read_count++;
00554 #else
00555   state.reg_61 &= ~0x20;
00556   state.reg_61 |= (state.pit_status[2] & 0x80) >> 2;
00557 #endif
00558   return state.reg_61;
00559 }
00560 
00564 void CAliM1543C::reg_61_write(u8 data)
00565 {
00566   state.reg_61 = (state.reg_61 & 0xf0) | (((u8) data) & 0x0f);
00567 }
00568 
00572 u8 CAliM1543C::toy_read(u32 address)
00573 {
00574 
00575   //printf("%%ALI-I-READTOY: read port %02x: 0x%02x\n", (u32)(0x70 + address), state.toy_access_ports[address]);
00576   return(u8) state.toy_access_ports[address];
00577 }
00578 
00582 void CAliM1543C::toy_write(u32 address, u8 data)
00583 {
00584   time_t      ltime;
00585   struct tm   stime;
00586   static long read_count = 0;
00587   static long hold_count = 0;
00588 
00589   //printf("%%ALI-I-WRITETOY: write port %02x: 0x%02x\n", (u32)(0x70 + address), data);
00590   state.toy_access_ports[address] = (u8) data;
00591 
00592   switch(address)
00593   {
00594   case 0:
00595     if((data & 0x7f) < 14)
00596     {
00597       state.toy_stored_data[0x0d] = 0x80;   // data is geldig!
00598 
00599       // update clock.......
00600       time(&ltime);
00601       gmtime_s(&stime, &ltime);
00602       if(state.toy_stored_data[0x0b] & 4)
00603       {
00604 
00605         // binary
00606         state.toy_stored_data[0] = (u8) (stime.tm_sec);
00607         state.toy_stored_data[2] = (u8) (stime.tm_min);
00608         if(state.toy_stored_data[0x0b] & 2) // 24-hour
00609           state.toy_stored_data[4] = (u8) (stime.tm_hour);
00610         else
00611           // 12-hour
00612           state.toy_stored_data[4] = (u8) (((stime.tm_hour / 12) ? 0x80 : 0) | (stime.tm_hour % 12));
00613         state.toy_stored_data[6] = (u8) (stime.tm_wday + 1);
00614         state.toy_stored_data[7] = (u8) (stime.tm_mday);
00615         state.toy_stored_data[8] = (u8) (stime.tm_mon + 1);
00616         state.toy_stored_data[9] = (u8) (stime.tm_year % 100);
00617       }
00618       else
00619       {
00620 
00621         // BCD
00622         state.toy_stored_data[0] = (u8) (((stime.tm_sec / 10) << 4) | (stime.tm_sec % 10));
00623         state.toy_stored_data[2] = (u8) (((stime.tm_min / 10) << 4) | (stime.tm_min % 10));
00624         if(state.toy_stored_data[0x0b] & 2) // 24-hour
00625           state.toy_stored_data[4] = (u8) (((stime.tm_hour / 10) << 4) | (stime.tm_hour % 10));
00626         else
00627         { // 12-hour
00628           state.toy_stored_data[4] = (u8)
00629             (
00630               ((stime.tm_hour / 12) ? 0x80 : 0) |
00631                 (((stime.tm_hour % 12) / 10) << 4) | ((stime.tm_hour % 12) % 10)
00632             );
00633         }
00634 
00635         state.toy_stored_data[6] = (u8) (stime.tm_wday + 1);
00636         state.toy_stored_data[7] = (u8) (((stime.tm_mday / 10) << 4) | (stime.tm_mday % 10));
00637         state.toy_stored_data[8] = (u8) ((((stime.tm_mon + 1) / 10) << 4) | ((stime.tm_mon + 1) % 10));
00638         state.toy_stored_data[9] = (u8) ((((stime.tm_year % 100) / 10) << 4) | ((stime.tm_year % 100) % 10));
00639       }
00640 
00641       // Debian Linux wants something out of 0x0a.  It gets initialized
00642       // with 0x26, by the SRM
00643       // Ah, here's something from the linux kernel:
00644       //# /********************************************************
00645       //# * register details
00646       //# ********************************************************/
00647       //# #define RTC_FREQ_SELECT RTC_REG_A
00648       //#
00649       //# /* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
00650       //# * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
00651       //# * totalling to a max high interval of 2.228 ms.
00652       //# */
00653       //# # define RTC_UIP 0x80
00654       //# # define RTC_DIV_CTL 0x70
00655       //# /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
00656       //# # define RTC_REF_CLCK_4MHZ 0x00
00657       //# # define RTC_REF_CLCK_1MHZ 0x10
00658       //# # define RTC_REF_CLCK_32KHZ 0x20
00659       //# /* 2 values for divider stage reset, others for "testing purposes only" */
00660       //# # define RTC_DIV_RESET1 0x60
00661       //# # define RTC_DIV_RESET2 0x70
00662       //# /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
00663       //# # define RTC_RATE_SELECT 0x0F
00664       //#
00665       // The SRM-init value of 0x26 means:
00666       //  xtal speed 32.768KHz  (standard)
00667       //  periodic interrupt rate divisor of 32 = interrupt every 976.562 ms (1024Hz clock)
00668       if(state.toy_stored_data[0x0a] & 0x80)
00669       {
00670 
00671         // Once the UIP line goes high, we have to stay high for 2228us.
00672         hold_count--;
00673         if(hold_count == 0)
00674         {
00675           state.toy_stored_data[0x0a] &= ~0x80;
00676           read_count = 0;
00677         }
00678       }
00679       else
00680       {
00681 
00682         // UIP isn't high, so if we're looping and waiting for it to go, it
00683         // will take 1,000,000/(IPus*3) reads for a 3 instruction loop.
00684         // If it happens to be a one time read, it'll only throw our calculations
00685         // off a tiny bit, and they'll be re-synced on the next read-loop.
00686         read_count++;
00687         if(read_count > 1000000 / (IPus * 3))   // 3541 @ 847IPus
00688         {
00689           state.toy_stored_data[0x0a] |= 0x80;
00690           hold_count = (2228 / (IPus * 3)) + 1; // .876 @ 847IPus, so we add one.
00691         }
00692       }
00693 
00694       //# /****************************************************/
00695       //# #define RTC_CONTROL RTC_REG_B
00696       //# # define RTC_SET 0x80 /* disable updates for clock setting */
00697       //# # define RTC_PIE 0x40 /* periodic interrupt enable */
00698       //# # define RTC_AIE 0x20 /* alarm interrupt enable */
00699       //# # define RTC_UIE 0x10 /* update-finished interrupt enable */
00700       //# # define RTC_SQWE 0x08 /* enable square-wave output */
00701       //# # define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
00702       //# # define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
00703       //# # define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
00704       //#
00705       // this is set (by the srm?) to 0x0e = SQWE | DM_BINARY | 24H
00706       // linux sets the PIE bit later.
00707       //# /***********************************************************/
00708       //# #define RTC_INTR_FLAGS RTC_REG_C
00709       //# /* caution - cleared by read */
00710       //# # define RTC_IRQF 0x80 /* any of the following 3 is active */
00711       //# # define RTC_PF 0x40
00712       //# # define RTC_AF 0x20
00713       //# # define RTC_UF 0x10
00714       //#
00715     }
00716 
00717     state.toy_access_ports[1] = state.toy_stored_data[data & 0x7f];
00718 
00719     // register C is cleared after a read, and we don't care if its a write
00720     if(data == 0x0c)
00721       state.toy_stored_data[data & 0x7f] = 0;
00722     break;
00723 
00724   case 1:
00725     if(state.toy_access_ports[0] == 0x0b && data & 0x040) // If we're writing to register B, we make register C look like it fired.
00726       state.toy_stored_data[0x0c] = 0xf0;
00727     state.toy_stored_data[state.toy_access_ports[0] & 0x7f] = (u8) data;
00728     break;
00729 
00730   case 2:
00731     state.toy_access_ports[3] = state.toy_stored_data[0x80 + (data & 0x7f)];
00732     break;
00733 
00734   case 3:
00735     state.toy_stored_data[0x80 + (state.toy_access_ports[2] & 0x7f)] = (u8) data;
00736     break;
00737   }
00738 }
00739 
00768 u8 CAliM1543C::pit_read(u32 address)
00769 {
00770 
00771   //printf("PIT Read: %02" LL "x \n",address);
00772   u8  data;
00773   data = 0;
00774   return data;
00775 }
00776 
00780 void CAliM1543C::pit_write(u32 address, u8 data)
00781 {
00782 
00783   //printf("PIT Write: %02" LL "x, %02x \n",address,data);
00784   if(address == 3)
00785   { // control
00786     if(data != 0)
00787     {
00788       state.pit_status[address] = data; // last command seen.
00789       if((data & 0xc0) >> 6 != 3)
00790       {
00791         state.pit_status[(data & 0xc0) >> 6] = data & 0x3f;
00792         state.pit_mode[(data & 0xc0) >> 6] = (data & 0x30) >> 4;
00793       }
00794       else
00795       { // readback command 8254 only
00796         state.pit_status[address] = 0xc0; // bogus :)
00797       }
00798     }
00799   }
00800   else
00801   { // a counter
00802     switch(state.pit_mode[address])
00803     {
00804     case 0:
00805       break;
00806 
00807     case 1:
00808     case 3:
00809       state.pit_counter[address] = (state.pit_counter[address] & 0xff) |
00810         data <<
00811         8;
00812       state.pit_counter[address + PIT_OFFSET_MAX] = state.pit_counter[address];
00813       if(state.pit_mode[address] == 3)
00814       {
00815         state.pit_mode[address] = 2;
00816       }
00817       else
00818         state.pit_status[address] &= ~0xc0; // no longer high, counter valid.
00819       break;
00820 
00821     case 2:
00822       state.pit_counter[address] = (state.pit_counter[address] & 0xff00) | data;
00823 
00824       // two bytes were written with 0x00, so its really 0x10000
00825       if((state.pit_status[address] & 0x30) >> 4 == 3
00826        && state.pit_counter[address] == 0)
00827       {
00828         state.pit_counter[address] = 65536;
00829       }
00830 
00831       state.pit_counter[address + PIT_OFFSET_MAX] = state.pit_counter[address];
00832       state.pit_status[address] &= ~0xc0;   // no longer high, counter valid.
00833       break;
00834     }
00835   }
00836 }
00837 
00838 #define PIT_FACTOR  5000
00839 #define PIT_DEC(p)  p = (p < PIT_FACTOR ? 0 : p - PIT_FACTOR);
00840 
00849 void CAliM1543C::pit_clock()
00850 {
00851   int i;
00852   for(i = 0; i < 3; i++)
00853   {
00854 
00855     // decrement the counter.
00856     if(state.pit_status[i] & 0x40)
00857       continue;
00858     PIT_DEC(state.pit_counter[i]);
00859     switch((state.pit_status[i] & 0x0e) >> 1)
00860     {
00861     case 0: // interrupt at terminal
00862       if(!state.pit_counter[i])
00863       {
00864         state.pit_status[i] |= 0xc0;  // out pin high, no count set.
00865       }
00866       break;
00867 
00868     case 3: // square wave generator
00869       if(!state.pit_counter[i])
00870       {
00871         if(state.pit_status[i] & 0x80)
00872         {
00873           state.pit_status[i] &= ~0x80; // lower output;
00874         }
00875         else
00876         {
00877           state.pit_status[i] |= 0x80;  // raise output
00878           if(i == 0)
00879           {
00880             pic_interrupt(0, 0);        // counter 0 is tied to irq 0.
00881             //printf("Generating timer interrupt.\n");
00882           }
00883         }
00884 
00885         state.pit_counter[i] = state.pit_counter[i + PIT_OFFSET_MAX];
00886       }
00887 
00888       // decrement again, since we want a half-wide square wave.
00889       PIT_DEC(state.pit_counter[i]);
00890       break;
00891 
00892     default:
00893       break;  // we don't care to handle it.
00894     }
00895   }
00896 }
00897 
00901 void CAliM1543C::run()
00902 {
00903   try
00904   {
00905     for(;;)
00906     {
00907       Poco::Thread::sleep(1);
00908       if(StopThread)
00909         return;
00910       do_pit_clock();
00911     }
00912   }
00913 
00914   catch(Poco::Exception & e)
00915   {
00916     printf("Exception in Ali thread: %s.\n", e.displayText().c_str());
00917 
00918     // Let the thread die...
00919   }
00920 }
00921 
00922 #define PIT_RATIO 1
00923 
00932 void CAliM1543C::do_pit_clock()
00933 {
00934   static int  pit_counter = 0;
00935   if(pit_counter++ >= PIT_RATIO)
00936   {
00937     pit_counter = 0;
00938     pit_clock();
00939   }
00940 }
00941 
00942 #define PIC_STD     0
00943 #define PIC_INIT_0  1
00944 #define PIC_INIT_1  2
00945 #define PIC_INIT_2  3
00946 
00950 u8 CAliM1543C::pic_read(int index, u32 address)
00951 {
00952   u8  data;
00953 
00954   data = 0;
00955 
00956   if(address == 1)
00957     data = state.pic_mask[index];
00958 
00959 #ifdef DEBUG_PIC
00960   if(pic_messages)
00961     printf("%%PIC-I-READ: read %02x from port %"LL "d on PIC %d\n", data,
00962            address, index);
00963 #endif
00964   return data;
00965 }
00966 
00970 u8 CAliM1543C::pic_read_edge_level(int index)
00971 {
00972   return state.pic_edge_level[index];
00973 }
00974 
00978 u8 CAliM1543C::pic_read_vector()
00979 {
00980   if(state.pic_asserted[0] & 1)
00981     return state.pic_intvec[0];
00982   if(state.pic_asserted[0] & 2)
00983     return state.pic_intvec[0] + 1;
00984   if(state.pic_asserted[0] & 4)
00985   {
00986     if(state.pic_asserted[1] & 1)
00987       return state.pic_intvec[1];
00988     if(state.pic_asserted[1] & 2)
00989       return state.pic_intvec[1] + 1;
00990     if(state.pic_asserted[1] & 4)
00991       return state.pic_intvec[1] + 2;
00992     if(state.pic_asserted[1] & 8)
00993       return state.pic_intvec[1] + 3;
00994     if(state.pic_asserted[1] & 16)
00995       return state.pic_intvec[1] + 4;
00996     if(state.pic_asserted[1] & 32)
00997       return state.pic_intvec[1] + 5;
00998     if(state.pic_asserted[1] & 64)
00999       return state.pic_intvec[1] + 6;
01000     if(state.pic_asserted[1] & 128)
01001       return state.pic_intvec[1] + 7;
01002   }
01003 
01004   if(state.pic_asserted[0] & 8)
01005     return state.pic_intvec[0] + 3;
01006   if(state.pic_asserted[0] & 16)
01007     return state.pic_intvec[0] + 4;
01008   if(state.pic_asserted[0] & 32)
01009     return state.pic_intvec[0] + 5;
01010   if(state.pic_asserted[0] & 64)
01011     return state.pic_intvec[0] + 6;
01012   if(state.pic_asserted[0] & 128)
01013     return state.pic_intvec[0] + 7;
01014   return 0;
01015 }
01016 
01020 void CAliM1543C::pic_write(int index, u32 address, u8 data)
01021 {
01022   int level;
01023   int op;
01024 #ifdef DEBUG_PIC
01025   if(pic_messages)
01026     printf("%%PIC-I-WRITE: write %02x to port %"LL "d on PIC %d\n", data,
01027            address, index);
01028 #endif
01029   switch(address)
01030   {
01031   case 0:
01032     if(data & 0x10)
01033       state.pic_mode[index] = PIC_INIT_0;
01034     else
01035       state.pic_mode[index] = PIC_STD;
01036     if(data & 0x08)
01037     {
01038 
01039       // OCW3
01040     }
01041     else
01042     {
01043 
01044       // OCW2
01045       op = (data >> 5) & 7;
01046       level = data & 7;
01047       switch(op)
01048       {
01049       case 1:
01050 
01051         //non-specific EOI
01052         state.pic_asserted[index] = 0;
01053 
01054         //
01055         if(index == 1)
01056           state.pic_asserted[0] &= ~(1 << 2);
01057 
01058         //
01059         if(!state.pic_asserted[0])
01060           cSystem->interrupt(55, false);
01061 #ifdef DEBUG_PIC
01062         pic_messages = false;
01063 #endif
01064         break;
01065 
01066       case 3:
01067 
01068         // specific EOI
01069         state.pic_asserted[index] &= ~(1 << level);
01070 
01071         //
01072         if((index == 1) && (!state.pic_asserted[1]))
01073           state.pic_asserted[0] &= ~(1 << 2);
01074 
01075         //
01076         if(!state.pic_asserted[0])
01077           cSystem->interrupt(55, false);
01078 #ifdef DEBUG_PIC
01079         pic_messages = false;
01080 #endif
01081         break;
01082       }
01083     }
01084 
01085     return;
01086 
01087   case 1:
01088     switch(state.pic_mode[index])
01089     {
01090     case PIC_INIT_0:
01091       state.pic_intvec[index] = (u8) data & 0xf8;
01092       state.pic_mode[index] = PIC_INIT_1;
01093       return;
01094 
01095     case PIC_INIT_1:
01096       state.pic_mode[index] = PIC_INIT_2;
01097       return;
01098 
01099     case PIC_INIT_2:
01100       state.pic_mode[index] = PIC_STD;
01101       return;
01102 
01103     case PIC_STD:
01104       state.pic_mask[index] = data;
01105       state.pic_asserted[index] &= ~data;
01106       return;
01107     }
01108   }
01109 }
01110 
01114 void CAliM1543C::pic_write_edge_level(int index, u8 data)
01115 {
01116   state.pic_edge_level[index] = data;
01117 }
01118 
01119 #define DEBUG_EXPR  (index != 0 || (intno != 0 && intno > 4))
01120 
01124 void CAliM1543C::pic_interrupt(int index, int intno)
01125 {
01126 #ifdef DEBUG_PIC
01127   if(DEBUG_EXPR)
01128   {
01129     printf("%%PIC-I-INCOMING: Interrupt %d incomming on PIC %d", intno, index);
01130     pic_messages = true;
01131   }
01132 #endif
01133 
01134   // do we have this interrupt enabled?
01135   if(state.pic_mask[index] & (1 << intno))
01136   {
01137 #ifdef DEBUG_PIC
01138     if(DEBUG_EXPR)
01139       printf(" (masked)\n");
01140     pic_messages = false;
01141 #endif
01142     return;
01143   }
01144 
01145   if(state.pic_asserted[index] & (1 << intno))
01146   {
01147 #ifdef DEBUG_PIC
01148     if(DEBUG_EXPR)
01149       printf(" (already asserted)\n");
01150 #endif
01151     return;
01152   }
01153 
01154 #ifdef DEBUG_PIC
01155   if(DEBUG_EXPR)
01156     printf("\n");
01157 #endif
01158   state.pic_asserted[index] |= (1 << intno);
01159 
01160   if(index == 1)
01161     pic_interrupt(0, 2);  // cascade
01162   if(index == 0)
01163     cSystem->interrupt(55, true);
01164 }
01165 
01169 void CAliM1543C::pic_deassert(int index, int intno)
01170 {
01171   if(!(state.pic_asserted[index] & (1 << intno)))
01172     return;
01173 
01174   //  printf("De-asserting %d,%d\n",index,intno);
01175   state.pic_asserted[index] &= !(1 << intno);
01176   if(index == 1 && state.pic_asserted[1] == 0)
01177     pic_deassert(0, 2); // cascade
01178   if(index == 0 && state.pic_asserted[0] == 0)
01179     cSystem->interrupt(55, false);
01180 }
01181 
01182 static u32  ali_magic1 = 0xA111543C;
01183 static u32  ali_magic2 = 0xC345111A;
01184 
01188 int CAliM1543C::SaveState(FILE* f)
01189 {
01190   long  ss = sizeof(state);
01191   int   res;
01192 
01193   if(res = CPCIDevice::SaveState(f))
01194     return res;
01195 
01196   fwrite(&ali_magic1, sizeof(u32), 1, f);
01197   fwrite(&ss, sizeof(long), 1, f);
01198   fwrite(&state, sizeof(state), 1, f);
01199   fwrite(&ali_magic2, sizeof(u32), 1, f);
01200   printf("%s: %d bytes saved.\n", devid_string, (int) ss);
01201   return 0;
01202 }
01203 
01207 int CAliM1543C::RestoreState(FILE* f)
01208 {
01209   long    ss;
01210   u32     m1;
01211   u32     m2;
01212   int     res;
01213   size_t  r;
01214 
01215   if(res = CPCIDevice::RestoreState(f))
01216     return res;
01217 
01218   r = fread(&m1, sizeof(u32), 1, f);
01219   if(r != 1)
01220   {
01221     printf("%s: unexpected end of file!\n", devid_string);
01222     return -1;
01223   }
01224 
01225   if(m1 != ali_magic1)
01226   {
01227     printf("%s: MAGIC 1 does not match!\n", devid_string);
01228     return -1;
01229   }
01230 
01231   fread(&ss, sizeof(long), 1, f);
01232   if(r != 1)
01233   {
01234     printf("%s: unexpected end of file!\n", devid_string);
01235     return -1;
01236   }
01237 
01238   if(ss != sizeof(state))
01239   {
01240     printf("%s: STRUCT SIZE does not match!\n", devid_string);
01241     return -1;
01242   }
01243 
01244   fread(&state, sizeof(state), 1, f);
01245   if(r != 1)
01246   {
01247     printf("%s: unexpected end of file!\n", devid_string);
01248     return -1;
01249   }
01250 
01251   r = fread(&m2, sizeof(u32), 1, f);
01252   if(r != 1)
01253   {
01254     printf("%s: unexpected end of file!\n", devid_string);
01255     return -1;
01256   }
01257 
01258   if(m2 != ali_magic2)
01259   {
01260     printf("%s: MAGIC 1 does not match!\n", devid_string);
01261     return -1;
01262   }
01263 
01264   printf("%s: %d bytes restored.\n", devid_string, (int) ss);
01265   return 0;
01266 }
01267 
01299 void CAliM1543C::lpt_reset()
01300 {
01301   state.lpt_data = ~0;
01302   state.lpt_status = 0xd8;  // busy, ack, online, error
01303   state.lpt_control = 0x0c; // select, init
01304   state.lpt_init = false;
01305 }
01306 
01310 u8 CAliM1543C::lpt_read(u32 address)
01311 {
01312   u8  data = 0;
01313   switch(address)
01314   {
01315   case 0:
01316     data = state.lpt_data;
01317     break;
01318 
01319   case 1:
01320     data = state.lpt_status;
01321     if((state.lpt_status & 0x80) == 0 && (state.lpt_control & 0x01) == 0)
01322     {
01323       if(state.lpt_status & 0x40)
01324       { // test ack
01325         state.lpt_status &= ~0x40;  // turn off ack
01326       }
01327       else
01328       {
01329         state.lpt_status |= 0x40;   // set ack.
01330         state.lpt_status |= 0x80;   // set (not) busy.
01331       }
01332     }
01333     break;
01334 
01335   case 2:
01336     data = state.lpt_control;
01337   }
01338 
01339 #ifdef DEBUG_LPT
01340   printf("%%LPT-I-READ: port %d = %x\n", address, data);
01341 #endif
01342   return data;
01343 }
01344 
01348 void CAliM1543C::lpt_write(u32 address, u8 data)
01349 {
01350 #ifdef DEBUG_LPT
01351   printf("%%LPT-I-WRITE: port %d = %x\n", address, data);
01352 #endif
01353   switch(address)
01354   {
01355   case 0:
01356     state.lpt_data = data;
01357     break;
01358 
01359   case 1:
01360     break;
01361 
01362   case 2:
01363     if((data & 0x04) == 0)
01364     {
01365       state.lpt_init = true;
01366       state.lpt_status = 0xd8;
01367     }
01368     else
01369     {
01370       if(data & 0x08)
01371       {   // select bit
01372         if(data & 0x01)
01373         { // strobe?
01374           state.lpt_status &= ~0x80;  // we're busy
01375 
01376           // do the write!
01377           if(lpt && state.lpt_init)
01378             fputc(state.lpt_data, lpt);
01379           if(state.lpt_control & 0x10)
01380           {
01381             pic_interrupt(0, 7);
01382           }
01383         }
01384         else
01385         {
01386 
01387           // ?
01388         }
01389       }
01390     }
01391 
01392     state.lpt_control = data;
01393   }
01394 }
01395 
01399 void CAliM1543C::check_state()
01400 {
01401   if(myThread && !myThread->isRunning())
01402     FAILURE(Thread, "ALi thread has died");
01403 }
01404 
01405 CAliM1543C*   theAli = 0;

SourceForge.net Logo
Project space on SourceForge.net