HP41 - Programmable CAT1?



#2

Is there an mcode or synthetic program that will dump a CAT1 listing into a series of registers? It's not a feature any of my favorite modules, nor can I locate such a function in a quick search of the module documentation at TOS. Any help would be appreciated.


Regards,
Howard


#3

Hi Howard,

the -ML ROM (or M2K ROM) contains a few functions that you could use to achieve this, but these work only for XROM's (CAT 2), not for any other CAT. See the user code of XCAT in M2K ROM. I assume you would like to have a list of user code programs in your registers?

Meindert


#4

Hi Meindert,


Yes, I'm looking to write a program to store all user code programs in main memory onto a floppy.


Regards,
Howard


#5

I am not the foremost HP-41 expert, but I can't think of a way to get a CAT 1 listing into a usable format for your purpose.

But, in theory, it would be possible to replicate CAT 1 functionality using synthetic means. The Global Label / End chain pointer format is available, and could be used to construct a synthetic program that finds the first label before every END, as well as the last label in the chain, writing them to HP-IL disk as each one is identified. Using this method, there would be no need to store the labels in registers.

Dan


#6

Quote:
.. a synthetic program that finds the first label before every END,
as well as the last label in the chain..

Actually, I was thinking of finding every global label in the chain. I might (and probably would) prefer to use the first label in a given program as the name to store the program under.

Quote:
writing them to HP-IL disk as each one is identified. Using this method, there would be no need to store the labels in registers.

The advantage of storing them in registers is that it is more general. There's no reliance on HP/IL, so you could use this list to, for example, save programs to extended memory. The big disadvantage of this approach, which Mike's solution and yours get around is the possible lack of register space, especially if there are a lot of programs in memory. But I think a PCAT1 routine ought to be able to compute in advance whether this would be a problem. There's also the question of a routine like this destroying preexisting data. So perhaps the solution of doing the listing incrementally would be better. You could have X contain the index of the entry you wanted to start at, and Y a bbb.eee.ccc loop specifier for the data registers to use, which would also select multiple entries. A -1 in X would mean "reset". The routine could return the highest index number actually returned, in case the total number of entries left was exceeded.


Regards,
Howard



Edit to add signature

Edited: 26 Mar 2009, 5:32 p.m.


#7

"Actually, I was thinking of finding every global label in the chain. I might (and probably would) prefer to use the first label in a given program as the name to store the program under."

Given your stated purpose, finding all the labels in the chain is not very helpful and confuses what needs to be stored. The first global label in a program would seem to be the logical one to use. You can always rename it whatever you want upon the actual store.

Concerning storing them in registers, if you use the standard alpha format, you can't store label names of over 6 characters, seven being the supported number of characters in a label. You could store them as non-normalized, but then they are not real useful.

My theoretical solution should be able to be done using only synthetics. No M-Code required. M-Code would be faster and more efficient, as always, but not required. Once you load each label name sequencially in the Alpha Register, you can do with it what you want. Save it to HP-IL storage. Save it to Extended Memory. Save it to mag cards. Even put it in a register if you want (6 character limitation if being stored as alpha data).

Dan


#8

Ah, missed that disparity in register and label length. So PCAT1 would have to return one label at a time in alpha on successive calls. Using the alpha register has the benefit that registers need not be disturbed. Good idea.



The reason I want all global labels is for generality. I may want the first label, but you may want the last. Also, perhaps the label names are needed for some other purpose than to store the programs. Returning them all, plus the ENDs, on successive calls is slower, but more general.



The question I have about a synthetic FOCAL program has to do with lowering the curtain to expose the labels. You have to go all the way down to the .END. to get all the labels. Will the synthetic program driving happily execute when it's registers are interpreted as data by the rest of the system?



I actually think it might be fun to implement this in FOCAL and in mcode also. :)



Regards,
Howard


#9

Quote: "The question I have about a synthetic FOCAL program has to do with lowering the curtain to expose the labels. You have to go all the way down to the .END. to get all the labels. Will the synthetic program driving happily execute when it's registers are interpreted as data by the rest of the system?"

The HP-41CX operating system does not really care that what it considers 'memory registers' and 'program registers' overlap, as long as the user keeps things straight during execution (e.g. NOT writing into 'memory registers' that really need to remain 'program registers') and the program puts things back before the program finishes. The program counter is not checked to see if it remains in program mememory space during program execution. That is one benefit that can be taken advantage of on several occasions, such as running programs that are stored in Extended Memory without having to recall them to main memory.

Quote: "I actually think it might be fun to implement this in FOCAL and in mcode also. :) "

Yes it would!

Dan

#10

IMHO it would not be useful to save the CAT1 output in registers as at least by synthetic means you may create labels waaay too long to store in one register. An ASCII file in XFunction would be more useful. To get that I would add an HP-71B to the IL-Loop and make it a look like a printer for the HP-41. Then do CAT 1 in trace mode and transfer the result back to the HP-41.

Simple, isn't it!

Ciao.....Mike


#11

Hi, Mike


I think I can live with not being abe to process synthetically created labels over 7 characters long. A greater difficulty might be overflow of available registers with all the alpha labels. You'd need to store all END instructions in registers too, to account for the possibility of multiple global labels in a single program. Perhaps PCAT1 could be implemented so as to return just one label per call. Either it could return the Xth such label, or it could keep track of the last label returned in an I/O buffer and return the next one on successive calls. There would have to be some sort of reset mechanism for that to be useful. I think I favor the former solution.



That's an hilarious solution using the 71B! I think you might actually be able to do it, too. But I want my PCAT1 to work regardless of the presence or absence of an HP/IL loop.


Regards,
Howard


#12

Howard,

Do you want each file to have a seperate entry on the HP-IL drive? if not, there are some MCODE functions that write the whole main memory onto an IL-drive. They could be modified to only write all the program registers out (using reg c to figure out where to start and stop).

Cheers

Peter


#13

There are routines in the HP/IL interface module that will store and retrieve the whole calculator state (WRTA and READA). But I want to be able to take one of my 41s (or an emulator), loaded with a bunch of programs, and store them all out to HP/IL as separate programs. Then I can take another 41 (or an emulator) and selectively load some of those programs.



It ought to be possible to do this with synthetic programming, but I wonder about moving the curtain to uncover the program headers. It seems to me that a synthetic PCAT1 wouldn't be able to run in calculator RAM. (Of course, that's the case with mcode too.)


Regards,
Howard


#14

Quote:
There are routines in the HP/IL interface module that will store and retrieve the whole calculator state (WRTA and READA). But I want to be able to take one of my 41s (or an emulator), loaded with a bunch of programs, and store them all out to HP/IL as separate programs.
Although I can't offhand think of a built-in way to have a program store all the programs separately (it seems like I've done it but I'm rusty on HPIL storage now), WRTP does indeed write the alpha-specified program to HPIL storage without the overkill of WRTA. Is that not what you want to do?

#15

Yes, but I want to get the list of programs to save from the calc without having to do it manually :)


Regards,
Howard


#16

If I were trying to do that, I might use the "save all" to HP-IL then put together a utility on a computer to extract the individual programs to separate files. Not that I'm volunteering to write such a thing, mind you.


#17

That would probably be easier, Eric. But what if I want to store the programs to extended memory? :)



I'm not volunteering to write anything either - but I might give the mcode try :).

Regards,
Howard

#18

I believe that it is possible to do with with synthetic programming. And all synthetic programs can run in calculator RAM.

My sythetic programming skills are very rusty, but here is what I can put together for a flow chart.

Recall and process the c register to resolve the location of the permenant END (.END.)

Move the curtain down the appropriate amount to make the register containing the .END. recallable as a numeric register.

Decode the register to determine the address of the next highest Global Label or END. Read that label and store it if it is not an END.

Decode that register to decode the type (Label or END). If it is an end, determine if this is the last (first) label in the chain, and use that to return a designator (flag?) back to the calling routine that all labels have been processed. Grab the last label stored, and return to a mother routine for processing (program storage or whatever you want to do with it) after storing some intermediate pointers for the next time through the subroutine and moving the curtain back to where it belongs.

Not easy, but should work.

Dan


#19

two further suggestions/thoughts:

  1. There are Non-normalizing recalls available from quite a few roms (Zenrom, CCD, Sandbox, ...) So one could do this without having to disturb the curtain.
  2. I'm not sure but I think it could be possible to have an end go across a register boundary. Which would make decoding it a bit more tricky but still doable.

Part of me is actually quite surprised that such a PCAT1 routine does not exist...

Cheers

Peter


#20

Using non-normalizing recalls for other ROMs would be helpful, but since (AFAIK) these are micro-code functions, it would not be possible to reproduce them in a synthetic program.

Yes, the fact that an End can wrap between registers makes the address decoding a bit trickier, but not excessively so.

It is surprising that a PCAT1 type program does not exist. The HP-41CX has the EMDIRX for Extended memory, but no equivalent for program memory.

Dan


#21

... see the program I did over the weekend. It uses functions from the CCD and does not need any curtain lifting etc (and actually no synthetics either thanks to the CCD)

Cheers

Peter

#22

Dan,

I spent some more time thinking about this and currently I don't know how this can be done in synthetic FOCAL programming alone. At some point or the other one needs to do a non-normalizing RCL from a specific register and IIRC this can not be done with synthetics alone.

Allowing the use of the X/F module, I think there is a way using the EM. There are a couple of functions that don't normalize (see page 182 in KJ EFME or here )

The sequence would have to be something like this:

  1. Create/change type of a tmp file with length 2 in XM to Data
  2. Lower the curtain to make 3 registers around the desired address(as an end can and most alpha labels will span 2 and up to 3 registers) directly accessible (say R00-R02)
  3. Use SAVER (probably, not 100% sure) to save R00-R02 to the tmp file
  4. Change the file type to Asci (by moving the curtain and overwriting the file-type)
  5. Locate and read out the individual bytes from EM using ASCI access functions and ATOX
  6. Rinse and repeat

Probably not very fast but doable. There are some PPC module functions for which we have the FOCAL/synthetic listing that one could use to make some of the absolute register calculations and decoding. Yet it would seem to be a trickier undertaking than I first imagined (which might explain its absence) and would need at least the X/F module.

All in all, I'm glad we have MCODE... (and the CCD)

Would love to hear thoughts from others on this little problem.

Cheers

Peter


#23

I knew that there were exceptions to register normalization, and thought (mistakenly?) that it would be possible to use one of them to get the register. You have the best solution I can think of, below.

You might have to do something extra though. Their is a byte stored at the beginning of each record of an ASCII file that indicates the record length. You may need to create a 4 register file as an ASCII file, create a record that is 27 characters long (first byte is record length (27D), the following 27 characters are dummy characters, switch the file to data, SAVER as you describe below, but first SEEKPT to the second register (don't mess with the first, it has the record pointer in it that needs to be preserved), save the three target registers in the last three registers of EM file, and then change the file type back to ASCII, SEEKPT to the seventh character of the first record (0) and read the record into the alpha register.

Quite convoluted, to say the least.

Dan

#24

Well, at least you need a XFunc/XMem where you may save the programs your future routine found. If you like to store them on floppy - DARN! - you need an IL-Loop <VBG>. The _hilarious_ use of an HP-71B as a printer evolved only from the idea to re-use the the trace output of the build-in CAT 1. (That way I got allmost all ROMs.) I never tried to set up a floppy to catch trace output in a file.

For an IL-free solution I would not store any data in registers that is contained already in main memory, I would only save a hint where to find it. How about a buffer (one register is enough) with an ID you rarely use to store the last and 2nd to last address PCAT1 found something to tell the user. Without code to keep it at ON it may be flushed with PACK or OFF/ON. The adress of global labels are "chained" bottom up satarting with the permanent .END. (BTW, that is the reason that CAT 1 gets faster to the end of the list.) Do I need to tell more of my idea?

But, IMHO, those programs which build a ROM from user code need something similar to build the FAT. Nothing useful found there?

Ciao.....Mike


#25

Quote:
The _hilarious_ use of an HP-71B as a printer evolved only from the idea to re-use the the trace output of the build-in CAT 1. (That way I got allmost all ROMs.)

It's a great idea. It was"hilarious" in the sense something unexpected is. :)

Quote:
Without code to keep it at ON it may be flushed with PACK or OFF/ON.

Hmm. This would be an issue with any solution that tried to return different results on successive calls

Quote:
The adress of global labels are "chained" bottom up satarting with the permanent .END. (BTW, that is the reason that CAT 1 gets faster to the end of the list.) Do I need to tell more of my idea?

Right, this is the chain that would have to be walked with either mcode or FOCAL. The former wouldn't require moving the curtain, however.

Quote:
But, IMHO, those programs which build a ROM from user code need something similar to build the FAT. Nothing useful found there?

Ah! Great idea! Steal.. er..borrowing code is always easier :)

Quote:
Ciao.....Mike

Regards,
Howard

#26

Hi,

The program below will show in reverse sequence all alpha labels as per Owain’s request. It makes good use of CCD functions that help decode the ENDs and Alpha Lables (and thanks to Clonix, et al they should be available to most of us in some shape or form). I hope it is at least a useful starting point.

Usage:

  1. Execute a GTO.. (to be save…)
  2. XEQ ‘PCAT’
  3. See all alpha labels in reverse sequence.
PCAT only uses R00, leaving all other registers for any processing of the labels. Any such additional processing (e.g. saving to HP-IL) can be readily added to the LBL ‘CA’ (Check for Alpha label). An extension to only show the top level alpha is ‘straight forward and left to the ‘interested reader’ :-) (god, did I dread these words in my math books…)

The structure of the ENDs and alpha LBLs is (as everything else) exceptionally well explained on pp498-504 in Wlodeks ‘Extend your HP-41’ (if I’d be allowed only one book to bring about the HP-41, it would be this…). The first two bytes have always the structure |C bbbr | rrrr rrrr|. bbb is the number of bytes and r|rrrr rrrr| the number of registers to the next CAT 1 element. For alpha labels, this is followed by |F n+1 | kkkk kkkk | tttt tttt |…|, where n is the number of chars in the alpha label, |kkkk kkkk| is the keycode if it is assigned to a key and |ttttt tttt| are the chars.

CCD Functions used

  • ’DCD’ – decode a NNNin x and append to alpha
  • ‘A+’ - add one byte to the absolute address (in dec) in X
  • ‘PEEKB’ – read the byte from absolute address in X
  • ‘A+B’ – add the number of bytes in X to absolute address in Y
  • ‘S>’ – shift X one bit to the right
  • ‘bS?’ – check if the bit in X is set in the number in Y

Note: The listing below is not optimized for speed, elegance, length etc yet only meant as a starting point. (e.g. I used the unnecessary alpha labels and ends to test the program basically on itself…) I hope it is still helpful.

Cheers

Peter


LBL ‘PCAT’
RCL c
CLA
‘A’
DCD
ASHF
ASHF ;extract the right three digits = starting of .END.
XEQ ‘3H>D’ ;convert into dec
STO 00
A+
PEEKB
X<>Y
A+
PEEKB
X<>Y
RDN
XEQ ‘MA’ ;get distance in bytes to next CAT1 element
RCL 00
X<>Y
A+B ;abs address of next CAT1 element
STO 00
LBL 00
A+
PEEKB
X<>Y
A+
PEEKB
X<>Y
RDN
XEQ ‘MA’
X=0? ;first alpha label has 0 as distance to next CAT1 element
GTO ‘EXIT
RCL 00
X<>Y
A+B ;calc next CAT1 element’s abs addr
STO 00
XEQ ‘CA’ ;check if this is a alpha label
RCL 00
GTO 00
LBL ‘EXIT’
BEEP
END

LBL’3H>D’ ;convert 3-dig hex in alpha into dec in X
XEQ 14
16
x^2
*
XEQ 14
16
*
R^
+
XEQ 14
R^
+
RTN
LBL 14
64
ATOX
X>Y?
XEQ 13
48
-
RTN
LBL 13
7
-
RTN
END

LBL ‘MA’ – make alpha distance in bytes
192
- ;get rid of the leading ‘C’ nibble in the first byte
STO M
S> ;red rid of the r bit in the 2nd nibble which is bbbr
X<>M ;store number of bytes into M
0
bS? ;is the r-bit set?
XEQ 14
CLX
RCL M
X<>Y
7
*
+
RTN
LBL 14
CLX
896
ST+ Y
RTN
END

LBL ‘CA’ ;check if alpha label
PEEKB
241
-
X<0?
RTN
CLA
RDN
A-
LBL 01
A-
PEEKB
XTOA
RDN
DSE Y
GTO 01
AVIEW
;here you can ad any additional stuff you want to do with this label
RTN
END

.END.

Corrected typo in listing


Edited: 7 Apr 2009, 12:27 a.m. after one or more responses were posted


#27

Here's the gist of some out-of-band communications Pete and I have been having regarding this code. Using my CCD version A module, this code freezes every one of my three halfnut 41CX machines when the code attempts to AVIEW in CA. Pete diagnosed the problem as a bug in the CCD A module, that was fixed in the B version. Unfortunately, I'm having difficulty getting the CCD B module images to work in my NoV64. The symptoms are that some of the instructions, visible in CAT2, give NONEXISTENT when you XEQ them. DCD is one of the problematic functions. I'm going to try to load the CCD pages into HEPAX RAM on the NoV64 to see if that makes a difference. Does anyone recognize this symptom with the NoV32/64? My MLDL2000 is broken (bad memory, apparently) so I'm stuck unless I can get past this problem


Regards,
Howard


#28

Howard,

any news? Did you get it to work for you?

Cheers

Peter


#29

Hi, Peter.



I was stopped in my attempt to reset my Nov64 by the fact that there is no NovClr64.hex file in my distribution from Diego. I had intended to email him, or post here about it, but I didn't get around to it. I'm rushed at the moment, but I'll try to do a post here later regarding this.


Regards,
Howard


#30

Howard,

here is the Clean-Novram file for you: Clear NoV64

And here is the description from Diego on how to clean it.

Quote:
Regarding your question, there should be a CLR-RAM4.HEX file in your CD, and therefore in your working directory. This file not only erases the whole 64K of RAM but also checks its functionality by writing and reading very single word.

Once you burn that file into your NoV-64 just plug it into your calculator (make sure its running at normal speed). A good set of batteries is highly recommended. After about 25 seconds your calculator will Auto turn ON and a message will let you know the result of the checking/erasing procedure:

[CLR OK ] (the more likely... :-) or...

[NO CLR ] (some fault has been found... ) if this was the case, please repeat the procedure to make sure the failure is consistent.

Should it ends up as expected, turn your calculator OFF, remove NoV-64 and re-configure it as usual with HEPAX emulation and other images you may want... if any.


HTH

Peter
Clear NoV64


Edited: 3 Apr 2009, 4:15 p.m.


Possibly Related Threads…
Thread Author Replies Views Last Post
  who uses programmable calculators? John Ioannidis 24 6,681 06-18-2013, 04:11 PM
Last Post: Steve Simpkin
  HP85 Programmable ROM cardtridge 82929A-service ROM not working- inaki 2 1,935 04-25-2013, 08:08 AM
Last Post: inaki
  TI Programmable 88 - What we missed... Joerg Woerner 22 5,982 03-08-2012, 12:08 AM
Last Post: David Ramsey
  Local variables in RPN programmable? David Hayden 19 4,913 10-28-2011, 03:57 AM
Last Post: Marcus von Cube, Germany
  Manual for vintage Russian MK-61 RPN programmable calculator? Cristian Arezzini 14 3,889 10-15-2011, 07:03 AM
Last Post: Cristian Arezzini
  Finding prime factors on a "non-programmable" calculator Don Shepherd 6 2,253 09-05-2011, 10:11 AM
Last Post: Allen
  CMT-300 Programmable Measurement System Jeff Davis 0 881 05-01-2011, 08:24 PM
Last Post: Jeff Davis
  HP 65 programmable designnut 4 1,535 01-01-2011, 03:22 AM
Last Post: Thomas Okken
  Programmable ? Gilles Collas 5 1,645 02-27-2010, 01:02 PM
Last Post: Marcus von Cube, Germany
  OT: Retro programmable makes comeback. Egan Ford 2 1,123 01-27-2010, 07:49 AM
Last Post: Bill (Smithville, NJ)

Forum Jump: