vc64web / virtualc64web

vc64web - Commodore C64 Emulator for iPad iPhone Android and the Web with CSDb access for thousands of demos at your fingertip.
https://vc64web.github.io/doc/about.html
GNU General Public License v3.0
45 stars 5 forks source link

load some floppies ... #8

Closed mithrendal closed 4 years ago

mithrendal commented 4 years ago

grafik

octopus in red 😎 loaded with the new introduced html5 file dialog

loading individual PRG files is fine, but the other types like CRT files and so on are not working yet, maybe I did something wrong in the code below ? I just guessed from the virtualC64 API names what could be appropriate and called that guys but nothing special happens ...


  if (checkFileSuffix(name, ".D64") || checkFileSuffix(name, ".d64")) {
    printf("isD64\n");
    //wrapper->c64->flash(D64File::makeWithBuffer(blob, len),0);
    wrapper->c64->drive1.insertDisk(D64File::makeWithBuffer(blob, len));
  }
  else if (checkFileSuffix(name, ".G64") || checkFileSuffix(name, ".g64")) {
    printf("isG64\n");
    wrapper->c64->drive1.insertDisk(G64File::makeWithBuffer(blob, len));
  }
  else if (checkFileSuffix(name, ".PRG") || checkFileSuffix(name, ".prg")) {
    printf("isPRG\n");
    wrapper->c64->flash(PRGFile::makeWithBuffer(blob, len),0);
  }
  else if (checkFileSuffix(name, ".CRT")|| checkFileSuffix(name, ".crt")) {
    printf("isCRT\n");
    wrapper->c64->expansionport.attachCartridge( Cartridge::makeWithCRTFile(wrapper->c64,(CRTFile::makeWithBuffer(blob, len))));
  }
dirkwhoffmann commented 4 years ago

loaded with the new introduced html5 file dialog

Very cool. Seems like out current lock down is a booster for retro development 🀀.

but nothing special happens ...

API calls look fine as far as I can tell πŸ€“. In case of a CRT, you need to reset the computer after attaching. Did you do that? To test the D64 case, we need to be able to type something useful inside the emulator, e.g., "LOAD "$",8 list "

mithrendal commented 4 years ago

In case of a CRT, you need to reset the computer after attaching. Did you do that?

Oh yes, that did the trick !!

  else if (checkFileSuffix(name, ".CRT")|| checkFileSuffix(name, ".crt")) {
    printf("isCRT\n");
    wrapper->c64->expansionport.attachCartridge( Cartridge::makeWithCRTFile(wrapper->c64,(CRTFile::makeWithBuffer(blob, len))));
    wrapper->c64->reset();
  }

seeing it here with a loaded crt file ...

grafik

BTW: of course Rambo is sitting in the heli ...

for the floppies I have setup an keyboard interface first and for commanding the heli I need a game controller interface ...

The pieces are all there in vC64 !!! Fitting them together is like going on a easter egg hunt in the garden... Every new working piece means an massive explosion of dopamin directly into rambos brain cells🀀🀀🀀...

dirkwhoffmann commented 4 years ago

seeing it here with a loaded crt file ...

Woohoo, Fort Apocalypse inside a cartridge inside a C64 inside a browser. Kind of a digital version of Russian Matrjoschkas 😎.

BTW: of course Rambo is sitting in the heli ...

Hmmm, not sure... wait... zooming in 🧐... coming closer... uhhhhh .... indeed 😳:

Unknown

I better not distract him too much. The blue heli usually appears from nowhere 😬.

The pieces are all there in vC64

If the puzzle gets too complicated, use me as a Siri interface. Like a Siri for API questions πŸ€“.

mithrendal commented 4 years ago

to be able to better view and understand the log output πŸ˜„ (it does scroll every 3 seconds) I decided to disable the c64 property takeAutoSnapshots ... but unfortunately it was declared as private 😱...

mainsdl.cpp:470:10: error: 'takeAutoSnapshots' is a private member of 'C64'
    c64->takeAutoSnapshots=false;
         ^
C64/C64.h:246:10: note: declared private here
    bool takeAutoSnapshots = true;
         ^
1 error generated.

I want to keep the C64 core as unpatched as possible ... but I just did it again 😩

    #ifdef __EMSCRIPTEN__
    public:
    #else
    private:
    #endif
    //! @brief    Indicates if snapshots should be taken automatically.
    bool takeAutoSnapshots = true;

I am very careful with the precious c64 core emulator, therefore all patches applied to the files in the folder C64 can be easily found by searching for the keyword EMSCRIPTEN

dirkwhoffmann commented 4 years ago

but unfortunately it was declared as private 😱

That's an easy one 😎.

Use C64::setTakeAutoSnapshots(false)

//
//! @functiongroup Handling snapshots
//

public:

//! @brief    Indicates if the auto-snapshot feature is enabled.
bool getTakeAutoSnapshots() { return takeAutoSnapshots; }

//! @brief    Enables or disabled the auto-snapshot feature.
void setTakeAutoSnapshots(bool enable) { takeAutoSnapshots = enable; }

/*! @brief    Disables the auto-snapshot feature temporarily.
 *  @details  This method is called when the snaphshot browser opens.
 */
void suspendAutoSnapshots() { autoSnapshotInterval -= (LONG_MAX / 2); }

/*! @brief    Heal a call to suspendAutoSnapshots()
 *  @details  This method is called when the snaphshot browser closes.
 */
void resumeAutoSnapshots() { autoSnapshotInterval += (LONG_MAX / 2); }

//! @brief    Returns the time between two auto-snapshots in seconds.
long getSnapshotInterval() { return autoSnapshotInterval; }

//! @brief    Sets the time between two auto-snapshots in seconds.
void setSnapshotInterval(long value) { autoSnapshotInterval = value; }

/*! @brief    Loads the current state from a snapshot file
 *  @note     There is an thread-unsafe and thread-safe version of this
 *            function. The first one can be unsed inside the emulator
 *            thread or from outside if the emulator is halted. The second
 *            one can be called any time.
 */
void loadFromSnapshotUnsafe(Snapshot *snapshot);
void loadFromSnapshotSafe(Snapshot *snapshot);
mithrendal commented 4 years ago

Had to rebase and roll that already pushed commit back. 😱 In which I made that guy public

Shame on me that I did not saw the setter methods. 😬

https://youtu.be/CWtS7jyhl-0

dirkwhoffmann commented 4 years ago

"Walk of Atonement" ... πŸ€” ... googling ... oh, Games of Thrones 😯

I never watches that series, because I usually have problems following movies and series with too many characters πŸ™„. I do love clean and simple concepts, and Games of Thrones seems to be the opposite (at least this is what I've heard).

Yesterday, I watched "Doom - The Movie" on Netflix which really has a clean a simple concept. The movie can be summarized easily: A gate to hell opens. Marines enter the gate.

Very clean and simple concept 😎. To be honest, it was much better than I thought.

mithrendal commented 4 years ago

I am at the point where I have to do the keyboard... there are different approaches ...

  1. do everything in the SDL event handler loop in C something like this
    
    case SDL_KEYUP:
     ...
            case SDLK_r:
              c64->keyboard.releaseKey(2, 1); //r;
              break;
     ...

2. do everything in javascript and just hand over the correct keycodes to a exported C method which then just presses what javascript wants...
something like this

javascript part

c64_key = Module.cwrap('js_key', 'undefined', ['string', 'number']);

function keydown(e) { //alert('keydown'+e.code); c64_key(e.code, 1); } function keyup(e) { //alert('keyup'+e.code); c64_key(e.code, 0); }

document.addEventListener('keyup', keyup);
document.addEventListener('keydown', keydown);

C part in mainsdl

extern "C" void js_key(char* keyCode, int pressed) { if(pressed==1) { wrapper->c64->keyboard.pressKey( ...); } else { wrapper->c64->keyboard.releaseKey(... ); } }



in 1. we could do all the event handling in mainsdl, which is simple but very closed to others... 

I like 2. approach much more because it is open and flexible  .... others could reuse the WASM binaries without the need of recompiling and add cool onscreen keyboards done in fancy HTML 

In my opinion we should strictly head to way2 and give javascript as much control as possible. we have already loadFile(CRT,D64...) ... as there is to come:  keyboard, game controller, toggleFullscreen, getSnapshot, loadSnapshot, reset, ...   
Keeping the event handling of WASM part only to an absolute minimum of very specific SDL related events ...  
dirkwhoffmann commented 4 years ago

In my opinion we should strictly head to way2 and give javascript as much control as possible.

Yes, I think that's the way to go. From the two major factors to consider here (speed and flexibility), speed is not an issue. Thus, I would also go for the more flexible approach.

Furthermore, we might want to have a virtual keyboard later 😍. Such a keyboard would have to interact with the JavaScript part, too, I guess.

BTW, do you have some oversight w.r.t. web GUI frameworks? Function wise, I think we should have something similar to SAE eventually. But maybe with a fancier look and feel (with animated controls, cool overlay effects, whatever is possible in modern HTML).

mithrendal commented 4 years ago

fancy webGUI, yes I want to have some responsive design here πŸ’ͺ🏾 😎. Responsive Design, because it should look also good on a mobile device. Maybe some bootstrap, jquery .... we will do that later !

BTW: I just tested on an iPhone6s with a connected bluetooth keyboard. Way2: It accepts the keys typed on the keyboard and directly passes them via javascript into the wasm part. Also Fullscreen button worked ... but screen ratio was a bit weird πŸ™ˆ... the well known effect of a fat robin hood in landscape and way to thin robin in portrait mode....

dirkwhoffmann commented 4 years ago

I just tested on an iPhone6s with a connected bluetooth keyboard

Wow, great progress. Sounds like you are on hyper-drive. I'm still fighting with vAmigas new snapshot / screenshot browser πŸ€“.

mithrendal commented 4 years ago

Sounds like you are on hyper-drive.

no not really 😍, familiy πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦ is asking for more social time with dad ... in the time between I just picking some low hanging fruits here and there. The path is clear now, I think it will slowly but steadily converge to an interesting thing...

Yes, I think that's the way to go. From the two major factors to consider here (speed and flexibility), speed is not an issue. Thus, I would also go for the more flexible approach.

Yep, for me now it has become competely clear that we must keep the C side wrapper in mainsdl.cpp as simple as possible without any additional logic and in the same time as open as possible to javascript.... All logic has to be done in the javascript part. That way the compiled WASM binary can be adapted to various browser environments, future browser changes .. without changing the C side part ...

I will prefix the C methods which are exported to Javascript with "wasm_" prefix ... with that way, on the C side, we know that the guy is for javascript. And on the javascript side, we know that it is the guy on the WASM side...

like this ...

javascript side...

    //init c wrappers
    wasm_loadfile = Module.cwrap('wasm_loadFile', 'undefined', ['string', 'array', 'number']);
    wasm_key = Module.cwrap('wasm_key', 'undefined', ['string', 'number']);
    wasm_toggleFullscreen = Module.cwrap('wasm_toggleFullscreen', 'undefined');
    ....
   //call c wrapper, for example load a file 
   wasm_loadfile(file.name, byteArray, byteArray.byteLength);

C side

extern "C" void wasm_loadFile(char* name, Uint8 *blob, long len)
{
...

I will make many of these 😎 until the Emulator is completely controllable from the javascript side.

mithrendal commented 4 years ago

keyboard works so far 😎 ... all done in javascript ... ok most keys ...enough to type Load"$",8,1 oder Load"*",8,1

Lets try to insert a disk ...


constructing C64 ...
adding a listener to C64 message queue...
vC64 message=MSG_PAL, data=0
vC64 message=MSG_VC1541_ATTACHED_SOUND, data=1
vC64 message=MSG_VC1541_ATTACHED, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_MOTOR_OFF, data=1
vC64 message=MSG_VC1541_NO_DISK, data=1
vC64 message=MSG_DISK_SAVED, data=1
vC64 message=MSG_PAL, data=0
vC64 message=MSG_NO_CARTRIDGE, data=0
vC64 message=MSG_CART_SWITCH, data=0
vC64 message=MSG_IEC_BUS_IDLE, data=0
vC64 message=MSG_VC1541_ATTACHED, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_MOTOR_OFF, data=1
vC64 message=MSG_VC1541_NO_DISK, data=1
vC64 message=MSG_DISK_SAVED, data=1
vC64 message=MSG_VC1541_DETACHED, data=2
vC64 message=MSG_VC1541_RED_LED_OFF, data=2
vC64 message=MSG_VC1541_MOTOR_OFF, data=2
vC64 message=MSG_VC1541_NO_DISK, data=2
vC64 message=MSG_DISK_SAVED, data=2
vC64 message=MSG_VC1530_NO_TAPE, data=0
vC64 message=MSG_VC1530_PROGRESS, data=0
vC64 message=MSG_WARP_OFF, data=0
vC64 message=MSG_ALWAYS_WARP_OFF, data=0
set SID to freq= 44100
Mouse entered window 1
Window 1 gained keyboard focus
Window 1 shown
Window 1 hidden
Window 1 gained keyboard focus
Window 1 shown
Window 1 size changed to 428x284
Size changed: 428, 284
wrapper calls 4x c64->loadRom(...) method
vC64 message=MSG_READY_TO_RUN, data=0
wrapper calls run on c64->run() method
vC64 message=MSG_RUN, data=0
vC64 message=MSG_IEC_BUS_BUSY, data=0
Window 1 lost keyboard focus
vC64 message=MSG_IEC_BUS_IDLE, data=0
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_MOTOR_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_MOTOR_OFF, data=1
vC64 message=MSG_IEC_BUS_BUSY, data=0
vC64 message=MSG_IEC_BUS_IDLE, data=0
load file=Blue_Max_[Synapse_1983].g64 len=333744
isG64
Assertion failed: insertionStatus == PARTIALLY_INSERTED, at: C64/Drive/Drive.cpp,483,insertDisk

uupps πŸ™ˆwhen I insert a disk an assertion comes up ...

what am I missing ?

maybe

  else if (checkFileSuffix(name, ".G64") || checkFileSuffix(name, ".g64")) {
    printf("isG64\n");
    wrapper->c64->drive1.insertDisk(G64File::makeWithBuffer(blob, len));
  }

is not sufficient ? It complains PARTIALLY_INSERTED .... Do I have to close the drive door per API call ? 🧐

or maybe do some VC1541::prepareToInsert() voodooo dance ?

dirkwhoffmann commented 4 years ago

familiy is asking for more social time with dad ... in the time between I just picking some low hanging fruits here and there

I see, a classical text-book example of a time constraint. Here, I’m faced with space constraints. My wife says I am turning our house into a museum 😯. But hey, it’s just 5 Amiga 500s, a C64, and an Atari 2600. And the C64 is not even an original C64. It's a C64 Maxi manufactured in 2019. Therefore it can never count a museum item πŸ™„.

or maybe do some VC1541::prepareToInsert() voodooo dance ?

Exactly. Emulating a C64 is brutal in the sense that many games rely on tiny aspects seen in real-life. As a result, even disk changes have to be emulated accurately. When a disk is inserted into the 1541 in real-life, the write-protection sensor gets blocked, independent of the protection status of the disk. Only when the disk got fully in (which requires a certain delay), the sensor gets unblocked for protected disks. To mimic this with VirtualC64, you need to do something similar to what the GUI does here:

     if disk != nil {
            drive.prepareToInsert()
            usleep(300000)
            drive.insertDisk(disk as? AnyArchiveProxy)
        }

prepareToInsert is a simple function that blocks the write-protection sensor. In addition, it sets the drive disk status to PARTIALLY_INSERTED to crash the emulator in insertDisk()if somebody skips the preparation step πŸ˜‰.

void
VC1541::prepareToInsert()
{
    c64->resume();

    debug("prepareToInsert\n");
    assert(insertionStatus == NOT_INSERTED);

    // Block the light barrier by taking the disk half out
    insertionStatus = PARTIALLY_INSERTED;

    c64->resume();
}

After calling this function, you are entitled to call insertDisk(…). The GUI code waits 0.3 sec between the calls which seems to work pretty well.

🀭 Just spotted a bug in the code above. I am calling resume() twice 😲. The code is supposed to look like this:

void
VC1541::prepareToInsert()
{
    suspend();

    debug("prepareToInsert\n");
    assert(insertionStatus == NOT_INSERTED);

    // Block the light barrier by taking the disk half out
    insertionStatus = PARTIALLY_INSERTED;

    resume();
}

I guess I have to this Games of Thrones walk now. No? 😬

mithrendal commented 4 years ago

ok lets applying the latest patches to the core (the double resume horror thing) ...

and

patching the wrapper code with the prepare thing...

it now looks like this

  if (checkFileSuffix(name, ".G64") || checkFileSuffix(name, ".g64")) {
    printf("isG64\n");
    wrapper->c64->drive1.prepareToInsert();
    usleep(300000);
    wrapper->c64->drive1.insertDisk(G64File::makeWithBuffer(blob, len));
    printf("wasm_loadFile: disk inserted\n");
  }

πŸ€“ Today is patch day

and lets insert the disk and hopefully the cores complaint about the partial insertion is gone ....

...
load file=Blue_Max_[Synapse_1983].g64 len=333744
isG64
vC64 message=MSG_VC1541_DISK, data=1
vC64 message=MSG_DISK_SAVED, data=1
vC64 message=MSG_VC1541_DISK_SOUND, data=1
wasm_loadFile: disk inserted
wasm_key ( 5, 2, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 5, 2, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 1, 7, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 4, 6, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 4, 6, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 7, 3, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 7, 3, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 1, 7, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 1, 7, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 1, 3, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 1, 3, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 7, 3, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 7, 3, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 1, 7, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 5, 7, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 5, 7, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 3, 3, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 3, 3, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 5, 7, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 5, 7, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 7, 0, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 7, 0, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 0, 1, 1 ) 
vC64 message=MSG_KEYMATRIX, data=0
wasm_key ( 0, 1, 0 ) 
vC64 message=MSG_KEYMATRIX, data=0
vC64 message=MSG_IEC_BUS_BUSY, data=0
vC64 message=MSG_VC1541_MOTOR_ON, data=1
vC64 message=MSG_VC1541_HEAD_UP, data=1
vC64 message=MSG_VC1541_HEAD_UP_SOUND, data=1
vC64 message=MSG_IEC_BUS_IDLE, data=0
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_UP, data=1
vC64 message=MSG_VC1541_HEAD_UP_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_HEAD_DOWN_SOUND, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_UP, data=1
vC64 message=MSG_VC1541_HEAD_UP_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_HEAD_DOWN_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_HEAD_DOWN_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_UP, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_UP, data=1
vC64 message=MSG_VC1541_HEAD_UP_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_HEAD_DOWN_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_IEC_BUS_BUSY, data=0
vC64 message=MSG_IEC_BUS_IDLE, data=0

Yes !! Strike back. It is really gone ! 😎

lets load the directory listing and see whats in there ...

grafik

ok lets load ... grafik

lets llloooooaaaadddd

grafik

it loads really reeeeaaallllyyy slllloooowwww.

BTW: he is my favourite actor in this film https://www.youtube.com/watch?v=LZqvEcR_lDg

it does load forever .... 😭

dirkwhoffmann commented 4 years ago

grafik

Your webcam is on again 🀭.

BTW: he is my favourite actor in this film

Oups, sorry, I thought it was the webcam πŸ™„.

it does load forever .... 😭

This is strange. The messages show that the drive head is moving. At the end, the IEC bus goes idle which means that there is no more bus activity (no more data transfer between the VC1541 and the C64). Did you check the D64 in the original VirtualC64? πŸ€”

mithrendal commented 4 years ago

Your webcam is on again 🀭.

yes true. Again.

Oups, sorry, I thought it was the webcam πŸ™„.

indeed it was 😳... the actor in my favourite film is my brother ...

Did you check the D64 in the original VirtualC64? πŸ€”

yes it loads

LOAD"$",8
searching for $
loading
ready

also other disks are stuck on searching for $ ....

do we have to debug ?? Patch the drive with some log output ?? Can you give me a hint where ? In case you like to have a look yourself ... I will push the current thing to the dev branch ...

dirkwhoffmann commented 4 years ago

do we have to debug ??

There are two major bug sources I could think of. 1) There might be some issue with the D64 file. 2) There might be an issue with the drive itself.

For 2), I think it's best to get some log output from the IEC bus. One of the main functions is this one:

void
IEC::updateIecLines()
{
    bool signals_changed;

    // Update bus lines
    signals_changed = _updateIecLines();    

    if (signals_changed) {

        c64->cia2.updatePA();

        // ATN signal is connected to CA1 pin of VIA 1
        c64->drive1.via1.CA1action(!atnLine);
        c64->drive2.via1.CA1action(!atnLine);

        if (tracingEnabled()) {
            dumpTrace();
        }
    ....

As you can seen, there is already some tracing support included. To start tracing the IEC bus, you can invoke method

void startTracing(int counter = -1) { traceCounter = counter; }

on the object to be traced. To enable it, add

iec->startTracing(1000); // Generates 1000 lines of trace output

to the constructor of the C64 class (C64::C64())

The trace output could then be compared to the original VirtualC64 output (with tracing enabled).

dirkwhoffmann commented 4 years ago

In the meantime, I can try to add some checksum support to VirtualC64 (back ported from vAmiga). This would tell us if the D64 data is OK.

dirkwhoffmann commented 4 years ago

There is a new brach in the VirtualC64 repo called β€žchecksumβ€œ. The revision in this branch produces some important debug output for us. If a D64 file is inserted, two checksums are written to the console. One checksum is computed out of the D64 file data and the other one out of the GCR encoded data. E.g., my version of agents.d64 produces:

...
D64Archive: readFromBuffer: checksum = 5b8c08e0f4c3b181
...
Drive1: insertDisk: checksum = 890168ff800908d7
...

If those checksums are different in VirtualC64 and VirtualC64web, we’ll know that there is some issue with the D64 files. This should be checked first.

To use the checksum feature in other code places, simply call this (global) function from anywhere in the code:

uint64_t fnv_1a_64(const uint8_t *addr, size_t size);
mithrendal commented 4 years ago

vc64web with checksum patch

grafik

vc64 checksum from branch

DragAndDrop.50::draggingEntered(_:): Dragged in filename
WindowDelegate.161::adjustWindowSize()
MyDocument.71::createAttachment(from:): Creating attachment from URL Blue_Max_[Synapse_1983].g64.
MyDocument.97::createAttachment(from:ofType:): Read 333744 bytes from file Blue_Max_[Synapse_1983].g64.
G64Archive: readFromBuffer: checksum = c73d1582c2971e92
MyDocument.194::mountAttachment(action:text:): Action = openBrowser
UserDialogController.16::showSheet(completionHandler:)
Animation.142::rotateBack(): Rotating back...
Drive1: prepareToInsert
Drive1: insertDisk
Drive1: insertDisk: checksum = 96c6da0a709de43c
dirkwhoffmann commented 4 years ago

Hmm, both checksums match. Actually, that's bad news, because this will be a nightmare to debug. Right now, I have no idea what could go wrong. 😬

dirkwhoffmann commented 4 years ago

Can you try to load the directory with LOAD "$",8, omitting the ,1?

mithrendal commented 4 years ago

yes I already tried that... load"$",8 without ,1 ... the same also no error in the logs it just becomes idle and stops ...

Files are ok because CRT and and PRGs work fine ... It must be something drive specific maybe timing related ? You know I had to replace the mach_time function with this guy. So the question is does the drive depend on timing ?

/* emulation of macos mach_absolute_time() function. */
long mach_absolute_time()
{
    auto xnow = std::chrono::system_clock::now();
    auto now_ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(xnow);
    auto epoch = now_ns.time_since_epoch();
    auto now_ns_long = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch).count();
    return now_ns_long;
}
dirkwhoffmann commented 4 years ago

What happens if you type LOAD "$",8without a disk present. Do you get the FILE NOT FOUND error message or does it freeze again?

mithrendal commented 4 years ago

LOAD "$",8 SEARCHING FOR $

and it logs endless LED On/off messages ...

no file not found error message ... nor device not present message ...

dirkwhoffmann commented 4 years ago

So the question is does the drive depend on timing ?

No, the mach_absolute_time()stuff only controls the speed of the emulator. The drive runs synchronously with the C64.

It could be some configuration issue. Maybe the original VirtualC64 is running in PAL mode and VirtualC64web in NTSC mode, or maybe some other config items differ. Every component has a dumpState()method. This could be used to compare the macOS version with the web version. πŸ€”

mithrendal commented 4 years ago

grafik

definitely manufactured for EU market ... 😎

dirkwhoffmann commented 4 years ago

Maybe I've got an idea. In original VirtualC64, the emulator is running in a separate thread. When the GUI wants to interact with it, it

But in VirtualC64web, the suspend / resume mechanism is no longer there. This means that inserting a disk happens while the emulator is running which is likely to create an inconsistent state. Does this make sense so far? If yes, we need to find a way to halt emulation before we modify the emulator state from outside (from outside = from the GUI).

mithrendal commented 4 years ago

I also photographed this ... feeling like a paparazzi .. 😬 grafik

mithrendal commented 4 years ago

If yes, we need to find a way to halt emulation before we modify the emulator state from outside (from outside = from the GUI).

I understand the idea, but we also get misbehaviour when we are not modifying any state ... by simply typing LOAD"$",8 with no disk it reads endless, that is not normal ... and we did not alter the emulation state or did we ?

dirkwhoffmann commented 4 years ago

Does this make sense so far?

Answering this myself: It doesn't make sense. It wouldn't explain the behavior with no disk present πŸ˜ͺ.

mithrendal commented 4 years ago

great minds think a like

mithrendal commented 4 years ago

So we know something is wrong with the drive, even without a disk inserted ... I think we have to test it ... with log statements

I will try to add iec->startTracing(1000); // Generates 1000 lines of trace output at the end of the constructor right after reset()??

dirkwhoffmann commented 4 years ago

I checked how the drive messages normally look like when reading a directory. For some arbitrary D64, I got this in original VirtualC64:

MyController.737::processMessage(_:): MSG_IEC_BUS_BUSY
MyController.754::processMessage(_:): MSG_VC1541_MOTOR_ON
MyController.760::processMessage(_:): MSG_VC1541_HEAD_UP
MyController.748::processMessage(_:): MSG_IEC_BUS_IDLE
MyController.763::processMessage(_:): MSG_VC1541_HEAD_DOWN
MyController.763::processMessage(_:): MSG_VC1541_HEAD_DOWN
MyController.763::processMessage(_:): MSG_VC1541_HEAD_DOWN
MyController.763::processMessage(_:): MSG_VC1541_HEAD_DOWN
MyController.763::processMessage(_:): MSG_VC1541_HEAD_DOWN
MyController.763::processMessage(_:): MSG_VC1541_HEAD_DOWN
MyController.711::processMessage(_:): MSG_VC1541_RED_LED_ON
MyController.737::processMessage(_:): MSG_IEC_BUS_BUSY
MyController.724::processMessage(_:): MSG_VC1541_RED_LED_OFF
MyController.748::processMessage(_:): MSG_IEC_BUS_IDLE

The red drive led is switched on / off exactly once. In your log output, the red drive led blinks.

mithrendal commented 4 years ago

I see a lot of these ....

...
IEC: ATN: 1 CLK: 1 DATA: 1 vC64.html:1:528
IEC: ATN: 1 CLK: 0 DATA: 1 vC64.html:1:528
IEC: ATN: 1 CLK: 0 DATA: 0 vC64.html:1:528
IEC: ATN: 1 CLK: 1 DATA: 0 vC64.html:1:528
IEC: ATN: 1 CLK: 0 DATA: 1 vC64.html:1:528
IEC: ATN: 1 CLK: 0 DATA: 0 vC64.html:1:528
IEC: ATN: 1 CLK: 1 DATA: 0 vC64.html:1:528
IEC: ATN: 1 CLK: 0 DATA: 1 vC64.html:1:528
IEC: ATN: 1 CLK: 1 DATA: 1 vC64.html:1:528
IEC: ATN: 1 CLK: 0 DATA: 1 vC64.html:1:528
IEC: ATN: 1 CLK: 0 DATA: 0 vC64.html:1:528
IEC: ATN: 1 CLK: 1 DATA: 0 vC64.html:1:528
IEC: ATN: 1 CLK: 0 DATA: 1 vC64.html:1:528
IEC: ATN: 1 CLK: 0 DATA: 0 vC64.html:1:528
IEC: ATN: 1 CLK: 1 DATA: 0 vC64.html:1:528
IEC: ATN: 1 CLK: 0 DATA: 1
...

mine is here directly after load"$",8 with inserted disk


vC64 message=MSG_VC1541_MOTOR_ON, data=1
vC64 message=MSG_VC1541_HEAD_UP, data=1
vC64 message=MSG_VC1541_HEAD_UP_SOUND, data=1
vC64 message=MSG_IEC_BUS_IDLE, data=0
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_UP, data=1
vC64 message=MSG_VC1541_HEAD_UP_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_HEAD_DOWN_SOUND, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_UP, data=1
vC64 message=MSG_VC1541_HEAD_UP_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_HEAD_DOWN_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_HEAD_DOWN_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_UP, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_UP, data=1
vC64 message=MSG_VC1541_HEAD_UP_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_VC1541_HEAD_DOWN, data=1
vC64 message=MSG_VC1541_HEAD_DOWN_SOUND, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_RED_LED_ON, data=1
vC64 message=MSG_IEC_BUS_BUSY, data=0
vC64 message=MSG_IEC_BUS_IDLE, data=0
mithrendal commented 4 years ago

right after the load"$",8 the original vc64 has a lot of MSG_VC1541_HEAD_DOWN where the webedition LED blinks on/off ...

Maybe a message from commodore ? They wan't to tell us something ... I bet they want to say us that the drive is broken ...

dirkwhoffmann commented 4 years ago

You are using the same drive Rom in VirtualC64 and VirtualC64web, aren't you? I'm running out of ideas 😬.

dirkwhoffmann commented 4 years ago

Can you push the current code to the repo?

mithrendal commented 4 years ago

You are using the same drive Rom in VirtualC64 and VirtualC64web, aren't you?

yes, I suppose to

just pushed to dev branch

but be careful ... on examining to core, maybe it is out of control already and can explode ... nucleaire chain reaction ??? ☠️ You will see the debug output in the browsers javascript web console.

dirkwhoffmann commented 4 years ago

Can you push the current code to the repo?

OK, downloaded...

Is it possible to see the native VirtualC64 debug messages somewhere? πŸ€”

mithrendal commented 4 years ago

You will see the debug output in the browsers javascript web console. Every browser has this nowadays something like "menu->extra->webdeveloper -> Javascript Console or Web console"

to load a file just click on the gray drop zone .... or drag a file into the drop zone...

dirkwhoffmann commented 4 years ago

OK, I can see the debug messages now.

mithrendal commented 4 years ago

I have found the problem ... I just took out the aggressive compiler optimization level3 out... with no optimisation at all the drive loads normally

dirkwhoffmann commented 4 years ago

let me guess first

mithrendal commented 4 years ago

Oh sorry I was too late updating the post

mithrendal commented 4 years ago

now lets see whether it hopefully works with -O2 or -O1 ?!!

dirkwhoffmann commented 4 years ago

I just took out the aggressive compiler optimization level3 out...

🀭 Wow. I should run VirtualC64 with Xcode's sanitizer then. Compiler makers often make use of "undefined behavior" and many C/C++ programmers have such bugs in their code.

I learned that the hard way with a strange bug in Moira πŸ™„.

dirkwhoffmann commented 4 years ago

OK, running Sanitizer to see how VirtualC64 is performing... 🀀

Arghhh, lots of Sanitizer errors in reSID πŸ˜–. OK, I'm throwing reSID out temporarily...

Uhh, that sounds creepy: VirtualC64 has Shadow bytes 😬. Sounds like a disease 😷.

2020-04-05 18:41:51.379392+0200 VirtualC64[58492:2650510] SUMMARY: AddressSanitizer: heap-buffer-overflow TimeDelayed.cpp:72 in TimeDelayed<unsigned char>::writeWithDelay(unsigned char, unsigned char)
2020-04-05 18:41:51.379434+0200 VirtualC64[58492:2650510] Shadow bytes around the buggy address:
2020-04-05 18:41:51.379471+0200 VirtualC64[58492:2650510]   0x1c0400008dd0: fa fa fd fa fa fa fd fa fa fa 00 fa fa fa fd fa
dirkwhoffmann commented 4 years ago

The good: Sanitizer has revealed a HUGE memory overflow bug in VirtualC64. I've fixed that on the main branch. The bad: Although Sanitizer doesn't complain any more when running VirtualC64mac, VirtualC64web still freezes with the old optimization level.