Updated HP-65 Emulator

I’ve recently updated the HP-65 emulator. The new version says "1.02" if you choose [Menu/Display] [About].

There was a bug in how subroutines work (see hp-65 – testing subroutines) but there are a number of other changes too. These are:

  • better visability of the s3 to W/PRGM-RUN switch relationship
  • improved memory delete
  • improved memory full
  • f0 changes
  • new debugging option
  • load / save cards fixed

Improved Memory Delete

Switch to W/PRGM, see "00 00", press g DEL and you’d get a black display – nothing shown at all.

The code used to be:

function memorydelete() {
    var ptrpos = prgmem.indexOf(61);
    if (ptrpos > 1) {
        prgmem.splice(ptrpos-1, 1);
        prgmem.push(0);
    }
    buffer = prgmem[ptrpos-2];
    busy = 10;
    fs[5] = 0;  // for circular memory waiting
}

It got changed to:

function memorydelete() {    // modified fr. 24.07.2016
    var ptrpos = prgmem.indexOf(61);
    if (ptrpos > 1) {
        prgmem.splice(ptrpos-1, 1);
        prgmem.push(0);
        buffer = prgmem[ptrpos-2];
        busy = 10;
    } else {
        buffer = prgmem[0];  //2017-03-14. better - real thing crashes if ptr deleted (65Notes V1N1)
        busy = 5;
    }
    aarSetHwFlags();
}

The problem was doing a delete when the pointer is at step 000. In that case prgmem = [63, 61, … ], ptrpos was 1, it wouldn’t delete step 000 which is good but, buffer[ptrpos-2] was out of bounds. That crashed the javascript and left the sceen in "dispoff" (no digits displayed).

The new version always puts the start of memory marker (63) in the buffer if you try to delete step 0.

Credit goes to Francois Roulet for pointing out the problem and suggesting a fix.

Improved Memory Full

This one was also from Francois. The old code was quite messy. It looked like:

function memoryfull() {
    a[0] = prgmem[101];                   // hide [xs]
    if ( prgmem[100] == 61 ) {
        a[0] = a[0] + prgmem[99];
    } else {
        a[0] = a[0] + prgmem[100];
    }
    a[0] = a[0] & 0xF;                    //  1-digit mask
    if (prgmem[101] == 61) { fs[2] = 1; } // show [s] only if ptr 61 is present
}

The new code currently looks like this:

function memoryfull() {
    var idx;
    idx= prgmem.length-1;
//    if ((prgmem[idx]==61) ||(prgmem[idx]==57)) idx--;
//    if ((prgmem[idx]==61) ||(prgmem[idx]==57)) idx--;
    a[0] = (prgmem[idx]==0) ? 0 : 1;     // if last step is NOP ok, else mem full
    aarSetHwFlags();
}

The two commented out lines were additions by me being too smart for my own good. The idea was to find the real end of user program memory by stepping back through any pointers. However, that isn’t how it works. It just looks at what’s in prgmem[101]. Normally the pointer is somewhere before that so [101] is step 100. When you SST to step 100, the pointer moves to [101] and step 100 is in [100]. My concern was the presence of the pointer tricking "memoryfull" into thinking there was a non NOP at step 100 ie that memory was full.

In fact, the calculator relies on this behaviour. The handbook says (p60), "if the 100th step of program memory contains anything other than g NOP, the display in W/PRGM mode always appears with a dash on the right to let you know that program memory is full." On the same page, just above that text, is a picture showing a dash on the right and a g NOP in step 100. That seems wrong as, clearly, memory isn’t full. It has a g NOP in step 100.

What is happening is the pointer is at step 100. It is positioned in [101] just after the actual step in [100]. The memoryfull microinstruction sees the pointer and says memory is full. This triggers the code which shows the trailing minus. That microcode also checks the f2 flag, which gets set if you are at the end of program memory, and adds a leading minus if f2 is set. You see "- 35 00- " despite step 100 being a g NOP.

f0 Changes

The new emulator correctly sets and clears f0 so the matching microcode in the ROMs can be executed at the appropriate times. It works well for one of the two situations. There’s likely to be a small tweak after I fully trace the other code flow.

New Debugging Option

You always could tack on "?debug=1" to the URL to cause the emulator to come up and wait. It sits at microcode instruction 00000. That is how I traced the startup code.

I have added a debug=2 option that shows the pointers as they move around program memory. This changes what you see in [Menu/Display], [Program].

The start marker shows up as "key code" "99 63". The primary pointer shows up as "99 61" and the secondary pointer shows up as "99 57". The pointers are always just after the instruction they point to.

You can also copy and paste programs in here as usual. If you paste (or type) in a "99 61" or a "99 57" then the calculator will consider that to be the pointer.

I mainly used it when debugging the subroutine issue. It is interesting, and it is reassuring to see them, but it probably won’t be useful for much. But it’s there if you need it.

You have to have a "99 63" at the start if you manually insert the other pointers.

You can combine the two (?debug=3) to activate the new mode AND stop at microinstruction 00000.

Load / Save Cards Fixed

There were two variable with the same name. Internally, the f flags reside in an array, fs[]. The card read/write to browser local storage used a filesystem object called, fs.

The instant any f flag got set or cleared the fs object got overwritten. This meant you couldn’t load or save programs.

This has now been fixed. If you tap the card slot to write a program it gets saved and it’s there when you come back later and tap the slot to read one. This works even if you shut down your browser and come back days later.

Browsers can lose data (eg if you pick "clear all site data" or similar) so it’s always a good idea to also save important programs in the normal file system too.

It's only fair to share...Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUponDigg thisPin on PinterestEmail this to someone

Leave a Reply

Your email address will not be published. Required fields are marked *