00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00184 #include "StdAfx.h"
00185 #include "Serial.h"
00186 #include "System.h"
00187 #include "AliM1543C.h"
00188
00189 #include "lockstep.h"
00190
00191 #define RECV_TICKS 10
00192
00193 int iCounter = 0;
00194
00195 #define FIFO_SIZE 1024
00196
00197
00198
00202 CSerial::CSerial(CConfigurator* cfg, CSystem* c, u16 number) : CSystemComponent(cfg, c)
00203 {
00204 state.iNumber = number;
00205 breakHit = false;
00206 }
00207
00211 void CSerial::init()
00212 {
00213 listenPort = (int) myCfg->get_num_value("port", false, 8000 + state.iNumber);
00214
00215 char s[1000];
00216 char* nargv = s;
00217 int i = 0;
00218
00219 cSystem->RegisterMemory(this, 0,
00220 U64(0x00000801fc0003f8) - (0x100 * state.iNumber), 8);
00221
00222
00223 #if defined(_WIN32)
00224
00225
00226 WSADATA wsa;
00227 WSAStartup(0x0101, &wsa);
00228 #endif // defined (_WIN32)
00229 struct sockaddr_in Address;
00230
00231 socklen_t nAddressSize = sizeof(struct sockaddr_in);
00232
00233 listenSocket = (int) socket(AF_INET, SOCK_STREAM, 0);
00234 if(listenSocket == INVALID_SOCKET)
00235 {
00236 printf("Could not open socket to listen on!\n");
00237 }
00238
00239 Address.sin_addr.s_addr = INADDR_ANY;
00240 Address.sin_port = htons((u16) (listenPort));
00241 Address.sin_family = AF_INET;
00242
00243 int optval = 1;
00244 setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, (char*) &optval,
00245 sizeof(optval));
00246 bind(listenSocket, (struct sockaddr*) &Address, sizeof(Address));
00247 listen(listenSocket, 1);
00248
00249 printf("%s: Waiting for connection on port %d.\n", devid_string, listenPort);
00250
00251 WaitForConnection();
00252
00253 #if defined(IDB) && defined(LS_MASTER)
00254 struct sockaddr_in dest_addr;
00255 int result = -1;
00256
00257 throughSocket = socket(AF_INET, SOCK_STREAM, 0);
00258
00259 dest_addr.sin_family = AF_INET;
00260 dest_addr.sin_port = htons((u16) (base + number));
00261 dest_addr.sin_addr.s_addr = inet_addr(ls_IP);
00262
00263 printf("%s: Waiting to initiate remote connection to %s.\n", devid_string,
00264 ls_IP);
00265
00266 while(result == -1)
00267 {
00268 result = connect(throughSocket, (struct sockaddr*) &dest_addr,
00269 sizeof(struct sockaddr));
00270 }
00271 #endif
00272 state.rcvW = 0;
00273 state.rcvR = 0;
00274
00275 state.bLCR = 0x00;
00276 state.bLSR = 0x60;
00277 state.bMSR = 0x30;
00278 state.bIIR = 0x01;
00279 state.irq_active = false;
00280 myThread = 0;
00281
00282 printf("%s: $Id: Serial.cpp,v 1.48 2008/03/31 19:13:28 iamcamiel Exp $\n",
00283 devid_string);
00284 }
00285
00286 void CSerial::start_threads()
00287 {
00288 char buffer[5];
00289 if(!myThread)
00290 {
00291 sprintf(buffer, "srl%d", state.iNumber);
00292 myThread = new Poco::Thread(buffer);
00293 printf(" %s", myThread->getName().c_str());
00294 StopThread = false;
00295 myThread->start(*this);
00296 }
00297 }
00298
00299 void CSerial::stop_threads()
00300 {
00301 StopThread = true;
00302 if(myThread)
00303 {
00304 printf(" %s", myThread->getName().c_str());
00305 myThread->join();
00306 delete myThread;
00307 myThread = 0;
00308 }
00309 }
00310
00314 CSerial::~CSerial()
00315 {
00316 stop_threads();
00317 }
00318
00319 u64 CSerial::ReadMem(int index, u64 address, int dsize)
00320 {
00321 u8 d;
00322
00323 switch(address)
00324 {
00325 case 0:
00326 if(state.bLCR & 0x80)
00327 {
00328 return state.bBRB_LSB;
00329 }
00330 else
00331 {
00332 if(state.rcvR != state.rcvW)
00333 {
00334 state.bRDR = state.rcvBuffer[state.rcvR];
00335 state.rcvR++;
00336 if(state.rcvR == FIFO_SIZE)
00337 state.rcvR = 0;
00338 TRC_DEV4("Read character %02x (%c) on serial port %d\n", state.bRDR,
00339 printable(state.bRDR), state.iNumber);
00340 #if defined(DEBUG_SERIAL)
00341 printf("Read character %02x (%c) on serial port %d\n", state.bRDR,
00342 printable(state.bRDR), state.iNumber);
00343 #endif
00344 }
00345 else
00346 {
00347 TRC_DEV2("Read past FIFO on serial port %d\n", state.iNumber);
00348 #if defined(DEBUG_SERIAL)
00349 printf("Read past FIFO on serial port %d\n", state.iNumber);
00350 #endif
00351 }
00352
00353 return state.bRDR;
00354 }
00355
00356 case 1:
00357 if(state.bLCR & 0x80)
00358 {
00359 return state.bBRB_MSB;
00360 }
00361 else
00362 {
00363 return state.bIER;
00364 }
00365
00366 case 2:
00367 d = state.bIIR;
00368 state.bIIR = 0x01;
00369 return d;
00370
00371 case 3:
00372 return state.bLCR;
00373
00374 case 4:
00375 return state.bMCR;
00376
00377 case 5:
00378 if(state.rcvR != state.rcvW)
00379 state.bLSR = 0x61;
00380 else
00381 state.bLSR = 0x60;
00382 return state.bLSR;
00383
00384 case 6:
00385 return state.bMSR;
00386
00387 default:
00388 return state.bSPR;
00389 }
00390 }
00391
00392 void CSerial::WriteMem(int index, u64 address, int dsize, u64 data)
00393 {
00394 u8 d;
00395 char s[5];
00396 d = (u8) data;
00397
00398 switch(address)
00399 {
00400 case 0:
00401 if(state.bLCR & 0x80)
00402 {
00403
00404
00405 state.bBRB_LSB = d;
00406 }
00407 else
00408 {
00409
00410
00411 sprintf(s, "%c", d);
00412 write(s);
00413 TRC_DEV4("Write character %02x (%c) on serial port %d\n", d, printable(d),
00414 state.iNumber);
00415 #if defined(DEBUG_SERIAL)
00416 printf("Write character %02x (%c) on serial port %d\n", d, printable(d),
00417 state.iNumber);
00418 #endif
00419 eval_interrupts();
00420 }
00421 break;
00422
00423 case 1:
00424 if(state.bLCR & 0x80)
00425 {
00426
00427
00428 state.bBRB_MSB = d;
00429 }
00430 else
00431 {
00432
00433
00434 state.bIER = d;
00435 eval_interrupts();
00436 }
00437 break;
00438
00439 case 2:
00440 state.bFCR = d;
00441 break;
00442
00443 case 3:
00444 state.bLCR = d;
00445 break;
00446
00447 case 4:
00448 state.bMCR = d;
00449 break;
00450
00451 default:
00452 state.bSPR = d;
00453 }
00454 }
00455
00456 void CSerial::eval_interrupts()
00457 {
00458 state.bIIR = 0x01;
00459 if((state.bIER & 0x01) && (state.rcvR != state.rcvW))
00460 state.bIIR = 0x04;
00461 else if(state.bIER & 0x2)
00462 state.bIIR = 0x02;
00463 else
00464 state.bIIR = 0x01;
00465 if(state.bIIR > 0x01)
00466 {
00467 if(!state.irq_active)
00468 theAli->pic_interrupt(0, 4 - state.iNumber);
00469 }
00470 else
00471 {
00472 if(state.irq_active)
00473 theAli->pic_deassert(0, 4 - state.iNumber);
00474 }
00475 }
00476
00477 void CSerial::write(const char* s)
00478 {
00479 int val = send(connectSocket, s, (int) strlen(s) + 1, 0);
00480 }
00481
00482 void CSerial::receive(const char* data)
00483 {
00484 char* x;
00485
00486 x = (char*) data;
00487
00488 while(*x)
00489 {
00490 state.rcvBuffer[state.rcvW++] = *x;
00491 if(state.rcvW == FIFO_SIZE)
00492 state.rcvW = 0;
00493 x++;
00494 eval_interrupts();
00495 }
00496 }
00497
00501 void CSerial::run()
00502 {
00503 try
00504 {
00505 for(;;)
00506 {
00507 if(StopThread)
00508 return;
00509 execute();
00510 Poco::Thread::sleep(20);
00511 }
00512 }
00513
00514 catch(Poco::Exception & e)
00515 {
00516 printf("Exception in Serial thread: %s.\n", e.displayText().c_str());
00517
00518
00519 }
00520 }
00521
00527 void CSerial::check_state()
00528 {
00529 if(breakHit)
00530 serial_menu();
00531
00532 if(myThread && !myThread->isRunning())
00533 FAILURE(Thread, "Serial thread has died");
00534 }
00535
00536 void CSerial::serial_menu()
00537 {
00538 fd_set readset;
00539 unsigned char buffer[FIFO_SIZE + 1];
00540 ssize_t size;
00541 struct timeval tv;
00542 bool exitLoop = false;
00543
00544 cSystem->stop_threads();
00545
00546 write("\r\n<BREAK> received. What do you want to do?\r\n");
00547 write(" 0. Continue\r\n");
00548 #if defined(IDB)
00549 write(" 1. End run\r\n");
00550 #else
00551 write(" 1. Exit emulator gracefully\r\n");
00552 write(" 2. Abort emulator (no changes saved)\r\n");
00553 write(" 3. Save state to autosave.axp and continue\r\n");
00554 write(" 4. Load state from autosave.axp and continue\r\n");
00555 #endif
00556 while(!exitLoop)
00557 {
00558 FD_ZERO(&readset);
00559 FD_SET(connectSocket, &readset);
00560 tv.tv_sec = 60;
00561 tv.tv_usec = 0;
00562 if(select(connectSocket + 1, &readset, NULL, NULL, &tv) <= 0)
00563 {
00564 write("%SRL-I-TIMEOUT: no timely answer received. Continuing emulation.\r\n");
00565 break;
00566 }
00567
00568 #if defined(_WIN32) || defined(__VMS)
00569 size = recv(connectSocket, (char*) buffer, FIFO_SIZE, 0);
00570 #else
00571 size = read(connectSocket, &buffer, FIFO_SIZE);
00572 #endif
00573 switch(buffer[0])
00574 {
00575 case '0':
00576 write("%SRL-I-CONTINUE: continuing emulation.\r\n");
00577 exitLoop = true;
00578 break;
00579
00580 case '1':
00581 write("%SRL-I-EXIT: exiting emulation gracefully.\r\n");
00582 FAILURE(Graceful, "Graceful exit");
00583 exitLoop = true;
00584 break;
00585
00586 case '2':
00587 write("%SRL-I-ABORT: aborting emulation.\r\n");
00588 FAILURE(Abort, "Aborting");
00589 exitLoop = true;
00590 break;
00591
00592 case '3':
00593 write("%SRL-I-SAVESTATE: Saving state to autosave.axp.\r\n");
00594 cSystem->SaveState("autosave.axp");
00595 write("%SRL-I-CONTINUE: continuing emulation.\r\n");
00596 exitLoop = true;
00597 break;
00598
00599 case '4':
00600 write("%SRL-I-LOADSTATE: Loading state from autosave.axp.\r\n");
00601 cSystem->RestoreState("autosave.axp");
00602 write("%SRL-I-CONTINUE: continuing emulation.\r\n");
00603 exitLoop = true;
00604 break;
00605
00606 default:
00607 write("%SRL-W-INVALID: Not a valid answer.\r\n");
00608 }
00609 }
00610
00611 breakHit = false;
00612 cSystem->start_threads();
00613 }
00614
00615 void CSerial::execute()
00616 {
00617 fd_set readset;
00618 unsigned char buffer[FIFO_SIZE + 1];
00619 unsigned char cbuffer[FIFO_SIZE + 1];
00620 unsigned char* b;
00621
00622
00623 unsigned char *c;
00624 ssize_t size;
00625 struct timeval tv;
00626
00627 state.serial_cycles++;
00628 if(state.serial_cycles >= RECV_TICKS)
00629 {
00630 FD_ZERO(&readset);
00631 FD_SET(connectSocket, &readset);
00632 tv.tv_sec = 0;
00633 tv.tv_usec = 0;
00634 if(select(connectSocket + 1, &readset, NULL, NULL, &tv) > 0)
00635 {
00636 #if defined(_WIN32) || defined(__VMS)
00637
00638
00639 size = recv(connectSocket, (char*) buffer, FIFO_SIZE, 0);
00640 #else
00641 size = read(connectSocket, &buffer, FIFO_SIZE);
00642 #endif
00643
00644 extern int got_sigint;
00645 if(size == 0 && !got_sigint)
00646 {
00647 printf("%%SRL-W-DISCONNECT: Write socket closed on other end for serial port %d.\n",
00648 state.iNumber);
00649 printf("-SRL-I-WAITFOR: Waiting for a new connection on port %d.\n",
00650 listenPort);
00651 WaitForConnection();
00652 return;
00653 }
00654
00655 buffer[size + 1] = 0;
00656 b = buffer;
00657 c = cbuffer;
00658 while((ssize_t) (b - buffer) < size)
00659 {
00660 if(*b == 0x0a)
00661 {
00662 b++;
00663 continue;
00664 }
00665
00666 if(*b == IAC)
00667 {
00668 if(*(b + 1) == IAC)
00669 {
00670 b++;
00671 }
00672 else if(*(b + 1) >= WILL)
00673 {
00674 b += 3;
00675 continue;
00676 }
00677 else if(*(b + 1) == SB)
00678 {
00679 b += 2;
00680 while(*b != IAC && *(b + 1) != SE)
00681 b++;
00682 b += 2;
00683 continue;
00684 }
00685 else if(*(b + 1) == BREAK)
00686 {
00687 b += 2;
00688 breakHit = true;
00689 }
00690 else if(*(b + 1) == AYT)
00691 {
00692 }
00693 else
00694 {
00695 b += 2;
00696 continue;
00697 }
00698 }
00699
00700 *c = *b;
00701 c++;
00702 b++;
00703 }
00704
00705 *c = 0;
00706 this->receive((const char*) &cbuffer);
00707 }
00708
00709 state.serial_cycles = 0;
00710 }
00711
00712 eval_interrupts();
00713 }
00714
00715 static u32 srl_magic1 = 0x5A15A15A;
00716 static u32 srl_magic2 = 0x1A51A51A;
00717
00721 int CSerial::SaveState(FILE* f)
00722 {
00723 long ss = sizeof(state);
00724
00725 fwrite(&srl_magic1, sizeof(u32), 1, f);
00726 fwrite(&ss, sizeof(long), 1, f);
00727 fwrite(&state, sizeof(state), 1, f);
00728 fwrite(&srl_magic2, sizeof(u32), 1, f);
00729 printf("%s: %d bytes saved.\n", devid_string, (int) ss);
00730 return 0;
00731 }
00732
00736 int CSerial::RestoreState(FILE* f)
00737 {
00738 long ss;
00739 u32 m1;
00740 u32 m2;
00741 size_t r;
00742
00743 r = fread(&m1, sizeof(u32), 1, f);
00744 if(r != 1)
00745 {
00746 printf("%s: unexpected end of file!\n", devid_string);
00747 return -1;
00748 }
00749
00750 if(m1 != srl_magic1)
00751 {
00752 printf("%s: MAGIC 1 does not match!\n", devid_string);
00753 return -1;
00754 }
00755
00756 fread(&ss, sizeof(long), 1, f);
00757 if(r != 1)
00758 {
00759 printf("%s: unexpected end of file!\n", devid_string);
00760 return -1;
00761 }
00762
00763 if(ss != sizeof(state))
00764 {
00765 printf("%s: STRUCT SIZE does not match!\n", devid_string);
00766 return -1;
00767 }
00768
00769 fread(&state, sizeof(state), 1, f);
00770 if(r != 1)
00771 {
00772 printf("%s: unexpected end of file!\n", devid_string);
00773 return -1;
00774 }
00775
00776 r = fread(&m2, sizeof(u32), 1, f);
00777 if(r != 1)
00778 {
00779 printf("%s: unexpected end of file!\n", devid_string);
00780 return -1;
00781 }
00782
00783 if(m2 != srl_magic2)
00784 {
00785 printf("%s: MAGIC 1 does not match!\n", devid_string);
00786 return -1;
00787 }
00788
00789 printf("%s: %d bytes restored.\n", devid_string, (int) ss);
00790 return 0;
00791 }
00792
00793 void CSerial::WaitForConnection()
00794 {
00795 struct sockaddr_in Address;
00796 socklen_t nAddressSize = sizeof(struct sockaddr_in);
00797 const char* telnet_options = "%c%c%c";
00798 char buffer[8];
00799 char s[1000];
00800 char* nargv = s;
00801 int i = 0;
00802
00803 #if !defined(LS_SLAVE)
00804 char s2[200];
00805 char* argv[20];
00806
00807 strncpy(s, myCfg->get_text_value("action", ""), 999);
00808 s[999] = '\0';
00809
00810
00811 if(strcmp(s, ""))
00812 {
00813
00814
00815 while(*nargv)
00816 {
00817 argv[i] = nargv;
00818 if(nargv[0] == '\"')
00819 nargv = strchr(nargv + 1, '\"');
00820 if(nargv)
00821 nargv = strchr(nargv, ' ');
00822 if(!nargv)
00823 break;
00824 *nargv++ = '\0';
00825 i++;
00826 argv[i] = NULL;
00827 }
00828
00829 argv[i + 1] = NULL;
00830 strcpy(s2, argv[0]);
00831 nargv = s2;
00832 if(nargv[0] == '\"')
00833 {
00834 nargv++;
00835 *(strchr(nargv, '\"')) = '\0';
00836 }
00837
00838
00839 #if defined(_WIN32)
00840 _spawnvp(_P_NOWAIT, nargv, argv);
00841 #elif !defined(__VMS)
00842 pid_t child;
00843 int status;
00844 if(!(child = fork()))
00845 {
00846 execvp(argv[0], argv);
00847 FAILURE_1(Runtime,"Exec of '%s' failed.\n", argv[0]);
00848 }
00849 else
00850 {
00851 sleep(1);
00852 waitpid(child, &status, WNOHANG);
00853 if(kill(child, 0) < 0)
00854 {
00855 FAILURE_1(Runtime,"Exec of '%s' has failed.\n", argv[0]);
00856 }
00857 }
00858 #endif
00859 }
00860 #endif
00861 Address.sin_addr.s_addr = INADDR_ANY;
00862 Address.sin_port = htons((u16) listenPort);
00863 Address.sin_family = AF_INET;
00864
00865
00866 connectSocket = INVALID_SOCKET;
00867 while(connectSocket == INVALID_SOCKET)
00868 {
00869 connectSocket = (int) accept(listenSocket, (struct sockaddr*) &Address,
00870 &nAddressSize);
00871 }
00872
00873 state.serial_cycles = 0;
00874
00875
00876
00877 sprintf(buffer, telnet_options, IAC, DO, TELOPT_ECHO);
00878 this->write(buffer);
00879
00880 sprintf(buffer, telnet_options, IAC, DO, TELOPT_NAWS);
00881 write(buffer);
00882
00883 sprintf(buffer, telnet_options, IAC, DO, TELOPT_LFLOW);
00884 this->write(buffer);
00885
00886 sprintf(buffer, telnet_options, IAC, WILL, TELOPT_ECHO);
00887 this->write(buffer);
00888
00889 sprintf(buffer, telnet_options, IAC, WILL, TELOPT_SGA);
00890 this->write(buffer);
00891
00892 sprintf(s, "This is serial port #%d on AlphaSim\r\n", state.iNumber);
00893 this->write(s);
00894 }