6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 16, 2024 3:08 pm

All times are UTC




Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Tue Aug 26, 2003 3:26 pm 
Offline

Joined: Tue Aug 26, 2003 3:19 pm
Posts: 9
I'd want to build an Emulator base on win32,I refer some code and I can achieve instruction of 6502,but how to make the emulator run speed is the same of actual speed(about 4Mhz)?


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Aug 26, 2003 6:07 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1747
Location: Sacramento, CA
Skyler,

In my simulator, I poll the system timer, which increments every 1ms.

What I did is to let the simulator execute 1ms worth of instructions (4000 cycles @ 4MHz) then wait for that ms to end. Then, I do another 1ms worth of instructions and wait. For most programs, this is acceptable. Sound generation based on timing loops would not be accurate since the loops would not be equally timed.

In my next release, I am attempting to time each instruction more accurately by using timing loops, cycle counters, and feedback to equally space each instruction within the 1ms window.

You can download my simulator and the C source code from my web site.

http://65c02.tripod.com/

Good luck!

Daryl


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Aug 27, 2003 3:33 pm 
Offline

Joined: Wed Sep 04, 2002 4:08 pm
Posts: 57
Location: Iowa
For sound, you'd probably want to buffer up 4000 cycles worth of sound and pass that off to the Windows sound API as a 1ms buffer to play in the background, then work on the next 4000 cycles in another buffer. But you probably don't want to bit-bang sound from a simulator. As a matter of fact, (I haven't looked at this in a long time, and not to deeply at that), you could use the notification that Windows gives you that it's done with the buffer and ready for the next as your 1ms timer, instead of polling.

Scott


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Aug 28, 2003 1:43 am 
Offline

Joined: Tue Aug 26, 2003 3:19 pm
Posts: 9
8Bit,

Thanks for your help,I know how to do now,run 4000 cycly then wait for each ms to end is and good way for me.Because on my project,there are no sound generation^o^
And why I can't visit your web sits?Can you send my your code to my MailBox directly? [skyler@cnnb.net]
Thank you.

Skyler.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Aug 29, 2003 2:19 pm 
Offline

Joined: Wed Sep 04, 2002 4:08 pm
Posts: 57
Location: Iowa
Daryl & Skyler,

You might still want to consider doing a blocking wait in your simulators instead of polling a timer. Daryl, I checked your simulator's CPU usage, and it's at 99%. A quick way to do this would be to call the Sleep function for the time you need to wait.

Scott


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Aug 29, 2003 4:53 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1747
Location: Sacramento, CA
Scott,

First, I'm no expert on Windows programming. I read up on the sleep function and found that it only has millisecond resolution. I'm counting cycles within a 1ms window. If the CPU takes .38ms to process the instructions, I cannot tell it to sleep for .62ms.

I can only sleep for whole ms periods. Do you have any suggestions?

Daryl


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Aug 29, 2003 6:24 pm 
Offline

Joined: Wed Sep 04, 2002 4:08 pm
Posts: 57
Location: Iowa
Daryl,

Hmm.... I'm somewhat novice myself on the Win32 stuff. And for "no expert," your simulator sure seems cool. OK, enough flattery. Some suggestions:

1. If it was Linux (or UNIX), I'd say use pthread_cond_timedwait() which uses an absolute time; then, no matter how long your instructions took to execute, you'd be woken up on the next millisecond. For example, if your run your simulation at Aug 29th, 2003, at 1:20:15.0100, then execute 4000 cycles and sleep until Aug 29th, 2003, at 1:20:15.0101. There should be an equivalent "wait until absolute time" function in Win32, but I couldn't find it.

2. You can set up a separate thread using CreateThread, which waited on 1ms intervals and incremented a semaphore. Your 6502 thread would simply execute 4000 cycles and then wait on the semaphore. This may still be off because of the time taken between 1ms waits to post the semaphore.

3. You can increase the period of your simulation loop, for example, execute for an equivalent of 100 ms. Then, if it takes 38.5 ms to execute 400,000 cycles, you'll wait for the remaining 62 ms with an insignificant amount of real-time error. Of course, you may get some flicker in your simulation at 100ms, but if it's just a simulation for testing, it should be fine. Or trade off timing accuracy for smoothness.

There are a few more ways to do it, but the absolute time method (#1) is best (if Win32 provides it). If you can wake up on 1ms boundaries and execute your 4000 cycles, and then sleep until the next 1ms boundary, you'll be dead-on, and your program won't hog the CPU.

Scott


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Sep 17, 2003 7:21 am 
Offline

Joined: Tue Aug 26, 2003 3:19 pm
Posts: 9
If it can not finish 4000cycle per second.Such as PC speed is not so fast or current status is too busy.What can I do next ms?
I use MMTimer,It can produce MS event.and I run 4000cycle in it's callback function.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Sep 17, 2003 2:27 pm 
Offline

Joined: Wed Sep 04, 2002 4:08 pm
Posts: 57
Location: Iowa
If you are waiting for an absolute time, such as "wait until 9:22 am, 50.0001 seconds" and, after running 4000 cycles you find that it's already 50.0004 seconds, you simply run your next 4000 cycles--your wait function should return immediately. The simulation will run slow, but it will also run no faster than it would in real time.

If your PC is too slow to run a 6502 simulation at 4MHz, then it's probably too slow to run Windows. If your simulation is honestly too slow for a Windows box, then you should probably take some time to optimize it. If you're using DOS, then just poll anyway--nothing else but your simulation will be running.

I couldn't find much help on MM_TIMER; I'm using an older VisualStudio. Are you using MFC? Are you programming for NT/2000 or 95/98? Are you familiar with multithreaded programming?

Scott


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Sep 17, 2003 2:28 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1747
Location: Sacramento, CA
Skyler,

You could set a variable called target_cycles.

At the end of a ms period, if there are any unexecuted cycles, then set target_cycles = unexecuted cycles. If all the cycles were executed, set it to zero.

Now, before entering the next ms period, ADD 4000 to target_cycles and use that value as the number of cycles to execute.

Daryl


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Sep 17, 2003 6:26 pm 
Offline

Joined: Tue Aug 26, 2003 3:19 pm
Posts: 9
Daryl,

I know how to do now.thank you.

skyler

+++++++++++++++++++++++++++++++++++++++++++++++

Scott,

I think Daryl's way is a good way to resolve my problem.
Infact,the below code just occupy CPU usage just 2-4%.I think it will work fine in the future.
I'll set a target_cycles,once the computer is too busy to finish 4000 cycle in ms,this will make it correct.
I'm using SDK and I want my simulation can run in NT,98,2K and XP.I'm an beginer of C++,I don't know about MFC.:(
Below is the code I use in my project now.

Thank's for your help.

skyler

***********************************************************
Code:
CMMTimers::CMMTimers()
{
TIMECAPS   tc;
if (!Intilizatize)
   {
      if (TIMERR_NOERROR == ::timeGetDevCaps(&tc,sizeof(TIMECAPS)))
      {
         timerRes = min(max(tc.wPeriodMin,1),tc.wPeriodMax);
         timeBeginPeriod(timerRes);
      }
   }
}
CMMTimers::~CMMTimers()
{
   stopTimer();
   if (0 != timerRes)
   {
      timeEndPeriod(timerRes);
      timerRes = 0;
   }
}
void CALLBACK internalTimerProc(UINT id,UINT msg,DWORD dwUser,DWORD dw1,DWORD dw2)
{
   static char str[40];
   sprintf(str,"Cycle:%08d",MMTimer.Counter);
   TextOut(Debugger.hdcMSG,0,0,str,strlen(str));
   MMTimer.Counter++;
   if (CPU.RUN) CPU.EXE(4000);
}
bool CMMTimers::startTimer(void)
{
   bool   res = false;
   MMRESULT   RETURN;
   if (!Runing)
   {
      Counter=0;
      result = timeSetEvent(
         1,
         timerRes,
         internalTimerProc,
         (DWORD)this,
         TIME_PERIODIC
         );
      if (NULL != RETURN)
      {
         timerId = (UINT)RETURN;
         Runing=true;
         res = true;
      }
      return res;
   }
   return false;
}
bool CMMTimers::stopTimer()
{
   MMRESULT   RETURN;
   result = timeKillEvent(timerId);
   if (TIMERR_NOERROR == RETURN)
      timerId = 0;
   Runing = RETURN;
   return TIMERR_NOERROR == RETURN;
}

***********************************************************


Last edited by skyler on Fri Sep 19, 2003 5:09 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Sep 17, 2003 9:47 pm 
Offline

Joined: Wed Sep 04, 2002 4:08 pm
Posts: 57
Location: Iowa
Skyler,

Yeah, that looks like it'll work. The TIMER_PERIODIC is what really saves you. At 2% to 4%, I wouldn't worry about not getting the 4000 cycles done in time at all, but if you don't, you should get a callback for each millisecond missed.

After you start your timer you probably return back to Windows's message loop, which blocks and gives up the CPU until the timeouts occur.

Scott.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Sep 18, 2003 2:08 am 
Offline

Joined: Tue Aug 26, 2003 3:19 pm
Posts: 9
Scott,

Because I have not simulate the LCD controler,after do this,I think it will become slowly.
If it can finish each ms task,it will exit callback and return to windows's message loop.
If it can not do this,Can i insert the code below to translate windows's message before start next ms task?If I not to do this,windows will have no chance to translate message.I can't prove the code will work fine.

thank you.

skyler

******************************************************
Code:
void CALLBACK internalTimerProc(UINT id,UINT msg,DWORD dwUser,DWORD dw1,DWORD dw2)
{
        static char str[40];
        static bool Intime;
        do
        {
                T1=GetCurrentTime();
                sprintf(str,"Cycle:%08d",MMTimer.Counter);
                TextOut(Debugger.hdcMSG,0,0,str,strlen(str));
                MMTimer.Counter++;
                if (!CPU.RUN) return;
                CPU.EXE(4000);
                T2=GetCurrentTime();
                if ((T2-T1)>=1ms)
                {       
                        Intime=true;
                        DoEvent();
                }
                else
Intime=false;
        }
        while (Intime);
}

void DoEvent()
{   
   MSG msg;
        BOOL bRet;
   bRet = GetMessage( &msg, NULL, 0, 0 );
   if (bRet != -1)
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
}

******************************************************


Last edited by skyler on Fri Sep 19, 2003 5:10 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Sep 18, 2003 2:20 pm 
Offline

Joined: Wed Sep 04, 2002 4:08 pm
Posts: 57
Location: Iowa
Skyler,

Again, I'm only a novice at Windows programming. It seems to me that whether or not you finish your 4000 cycles in 1ms, you want to return to your message loop. Then if you couldn't complete your simulation in 1ms, a timeout message would be waiting for you immediately, wouldn't it?

Quote:
If I not to do this,windows will have no chance to translate message.


Are you sure? I'm not sure how it works since I've only used a little MFC, but I'd think that any messages posted to your application would simply be waiting in a queue when you get back to the message loop.

Scott


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Sep 18, 2003 7:26 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
Quote:
CMMTimers::CMMTimers()
{
TIMECAPS tc;
if (!Intilizatize)
{
if (TIMERR_NOERROR == ::timeGetDevCaps(&tc,sizeof(TIMECAPS)))
{
timerRes = min(max(tc.wPeriodMin,1),tc.wPeriodMax);
timeBeginPeriod(timerRes);
}
}
}


Folks, when posting code, can you please wrap it inside a CODE block? That's what it's there for, and it preserves spacing and indentation, which for C++, is *critical* for understanding the code.

This is what the above would look like if posted, verbatim, inside a code block:

Code:
CMMTimers::CMMTimers()
{
TIMECAPS   tc;
if (!Intilizatize)
   {
      if (TIMERR_NOERROR == ::timeGetDevCaps(&tc,sizeof(TIMECAPS)))
      {
         timerRes = min(max(tc.wPeriodMin,1),tc.wPeriodMax);
         timeBeginPeriod(timerRes);
      }
   }
}


Believe me, everyone will truely appreciate it. I know I sure do.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 0 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: