Login
Back to forumReply to this topicGo to last reply

Posted By

Csabo
on 2009-01-08
23:45:28
 Defining a custom charset from BASIC

As far as I know, the "traditional ways" are:

1) Write a small machine language copy routine, store the code in DATA, POKE it, call it with SYS.

2) Print the MONITOR, T ... command, X, RUN on screen, and execute it by simulating keystrokes. (Example: Qually)

3) A variation on 2) is to store the charset in a separate file and LOAD it. (Example: Ritter für den König).

There are a few more ways, but none of them are very elegant. I had an item on my long term to-do list, and that was to see if the built in monitor's T command could be called from BASIC with a SYS. Now that would be elegant. This issue came up recently and I spent the time looking into it. Advertisement: I used SVS' Ultimate Map, it's an excellent piece of information heap, check it out and USE IT if you haven't already.

Here's what I found: 16 bit values on $A1, $F0 and $9F are the source, destination and number of bytes to copy, respectively. $BB has to be set to $80 (to flag that this is the T command, and not C, the two use the same code). Then it can be called at $F5DF. So here's the small chunk of BASIC to actually do it (hooray for YAPE's copy/paste!). It's verbose and unoptimized on purpose (to make it easy to understand).

0 REM $A1: SOURCE                       
1 REM $F0: DEST
2 REM $9F: LENGTH, BYTES TO COPY
3 REM $BB: $80 TO FLAG COPY
4 REM $F5DF: T COMMAND ENTRY POINT
10 S = DEC("D000")
11 D = DEC("3800")
12 L = DEC("07FF")
13 POKE 161, S AND 255 : POKE 162, S/256
14 POKE 241, D AND 255 : POKE 242, D/256
15 POKE 159, L AND 255 : POKE 160, L/256
16 POKE 187,128
17 SYS 62943


It works, the original charset from $D000 is copied to our destination quickly and with minimal code. But (and you knew the BUT was coming wink) here's the problem: it quietly ends up back in monitor. This can be mitigated by the same old trick (see How to simulate keystrokes). But that kind of defeats the purpose... It's not elegant.

So, there it is, something to think about, perhaps someone will use it. Otherwise, maybe someone knows a way to prevent it from ending up in monitor? Or... is there some other built in ROM routine one could exploit to do the copying?

Posted By

Chicken
on 2009-01-09
04:16:09
 Re: Defining a custom charset from BASIC

Method "0." would be to copy the system charset in a POKE RAM/PEEK ROM loop. Very slow but it was done this way in some code examples and maybe even type-in games.

There's another slightly different way similar to the simulated key strokes. Define KEY 1 with a string that includes entering MONITOR, Transfering the charset, eXiting MONITOR and reRUN the program. Then use SYS xxxxx to call KEY 1. It's not elegant either, though

Posted By

Chicken
on 2009-01-09
06:57:23
 Re: Defining a custom charset from BASIC

Sheesh... I should get some sleep instead of posting bull :D

PEEK ROM? :D

Those slow loops I was refering to probably set up an entire redefinined charset and didn't copy the ROM charset before.

That nice "copy" routine at $88c7 just copies RAM, too Still useful sometimes.

Posted By

Csabo
on 2009-01-09
09:42:09
 Re: Defining a custom charset from BASIC

Right, actually what you mentioned as method zero is what I came across recently. It is really so painfully slow that any of the other methods are better, screw being elegant. Second, using that method goes out the window if you compile your BASIC with AustroSpeed, because then your loop will copy RAM instead

The idea to reprogram an F key is very nice, I like it a lot. It saves a lot of POKEs.

Posted By

Chicken
on 2009-01-10
05:49:33
 Re: Defining a custom charset from BASIC

And you don't need the simulated keystrokes when you do it that way. Unfortunately, I can't find the SYS that does the "KEY 1" thing. But I know it exists. Does anyone have it at hand? (As a workaround you can still do a simulated keystroke for the F-key of course.)

If you plan to compile a program it's probably the best thing to link the redefined charset and save everything as one file. Though, maybe in a limited size contest you don't want all the extra memory "wasted". But than you wouldn't compile anything either wink

Anyway, I wish there'd be an elegant way to do this... there must be one happy

Posted By

gerliczer
on 2009-01-10
09:19:25
 Re: Defining a custom charset from BASIC

There is a copy routine at $DA4F in the KERNAL ROM that one could trick into doing the necessary copying. It uses zero page addresses to determine the source and destination. A, X, Y and SP values can be passed when using SYS via addresses $07F2-07F5.

Posted By

Csabo
on 2009-01-11
10:55:18
 Re: Defining a custom charset from BASIC

The round of applause goes to gerliczer, he sent me a working proof of concept of his idea, which works perfectly! I simply changed the line breaks slightly, so the whole routine fits on one Plus/4 screen (and therefore can be copy/pasted wink)

10 REM SAVING ZERO PAGE VARIABLES      
11 C0=PEEK(192):C1=PEEK(193)
12 C8=PEEK(200):C9=PEEK(201)
13 A9=PEEK(169):AA=PEEK(170)
14 EA=PEEK(234):EB=PEEK(235)
15 REM SAVING ADDITIONAL VARIABLE
16 T=PEEK(2024)
17 REM SETTING UP ZERO PAGE ADDRESSES
18 REM $C0-$C1 SRC1 $C8-$C9 DEST1
19 REM $A9-$AA SRC2 $EA-$EB DEST2
20 POKE192,0 : POKE193,13*16
21 POKE200,0 : POKE201,3*16+8
22 POKE169,128 : POKE170,13*16
23 POKE234,128 : POKE235,3*16+8
24 REM SETTING UP ADDITIONAL VARIABLE
25 POKE2024,128
26 REM COPYING 256 BYTES FROM CHAR-GEN
27 SYSDEC("DA4F")
28 REM RESTORING ALL SAVED VALUES
29 POKE192,C0 : POKE193,C1
30 POKE200,C8 : POKE201,C9
31 POKE169,A9 : POKE170,AA
32 POKE234,EA : POKE235,EB
33 POKE2024,T

This copies 256 bytes from $D000 to $3800 very quickly. The routine (which I'm curious as to how he found it) copies two vectors, normally that would be character and color memory. I guess that means in one cycle we could copy two 256 byte pages. To copy the entire charset would need a simple loop. Other room for optimization would be to check if we can get away with not saving some of the zeropage variables, but this method is the holy grail happy

Posted By

Gaia
on 2009-01-11
16:07:47
 Re: Defining a custom charset from BASIC

Does the POKE command accept hexadecimal arguments? That is new to me happy

Posted By

Chicken
on 2009-01-11
17:58:29
 Re: Defining a custom charset from BASIC

Gaia...
Those are variables (representing the value of that particular zeropage address, therefore the names, I guess) not hexadecimal numbers happy

Gerliczer...
Brilliant happy Exactly the thing I had hoped for. I'll keep this in mind anyway. It's a good challenge to find another elegant way.

Posted By

gerliczer
on 2009-01-12
05:33:31
 Re: Defining a custom charset from BASIC

I checked the code again. It is probably safe to skip the saving of zero page variables. The program in its presented form actually copies 258 bytes but as the two areas overlap the number of copied bytes is 257. To copy exactly 256 one has to poke 127 to location 2024. When calling the routine in a loop one has to keep in mind not to forget resetting the Y register (2036) if less than 256 bytes were copied.
Finding the routine was a piece of cakehappy First I fired up YAPE and checked the reset routine as it must copy a lot for initializing the machine but found nothing. Then I opened our "Holy Bible" (http://plus4world.powweb.com/publications/PLUS4_Belso_Felepitese) and paging through the ROM disassembly looked for KERNAL routines that do some copying. I came across the cursor control section and found the screen scrolling part.
The backup variable names of zero page values were chosen to help me remember what to put where for restoring the original state. I never intended them to be funny but probably that's what really makes them that.
Calling this solution some kind of Holy Grail is a bit of exaggeration. This poking and calling undocumented "APIs" could be called anything but elegant. Saying efficient or butt ugly is much better. Loading the charset form a separate file is way closer to elegant.

Posted By

Gaia
on 2009-01-12
10:14:54
 Re: Defining a custom charset from BASIC

It was a (n apparently bad) joke happy

Posted By

Csabo
on 2009-01-12
13:10:09
 Re: Defining a custom charset from BASIC

I see you point on why you don't think we should call it elegant.

I guess I should have defined the original goals better. Being self-contained was a requirement for me, so loading an external file is out of the question. An external file also raises potential problems: was the program loaded from tape or disk, will the file be found, etc. Not to mention if you only want to overwrite a few characters, it's a waste (of both loading time and tape/disk space).

In "other" programming worlds I probably wouldn't do this either, but for the Plus/4, the ROM is pretty much set in stone happy

We can definitely agree to this: it works well, it's fast, it's definitely an option. Good job!

Posted By

MMS
on 2009-01-12
14:33:09
 Re: Defining a custom charset from BASIC

Great topic! I just recently suffered the original posted slowlyness of the charcset copy in BASIC with PEEKs and POKEs, which -in fact- seen in other sample programs also, published inn different books too. I cound not find an other way, and I am far from that level to able to call assembly routines from BASIC (that famous USR command). Do not ask why I wanted to use BASIC, maybe because it looks similar to Pascal happy

OFF: BTW, still one thing is unclear for me: why after Austrospeed compilation these BASIC PEEKs did not work? Maybe Austrospeed just cancelling the ROM/RAM banking, and that's why it become faster? As on one hand I need a faster copy, on the other hand I also need faster FOR routines happy But maybe I should really write something is assembly happy or try that very much undocumented C..

Posted By

Csabo
on 2009-01-12
16:42:58
 Re: Defining a custom charset from BASIC

Although it's trivial, here's the final optimized version. The loop only needs to run 4 times as we can copy 512 bytes with one SYS. I like it wink

10 D=DEC("38")

12 W=PEEK(2024):POKE2024,255
13 POKE192,0:POKE169,0
14 POKE200,0:POKE234,0
15 FORI=0TO3
16 POKE193,208+I:POKE170,212+I
17 POKE201,D+I:POKE235,D+4+I
18 POKE2036,0:SYSDEC("DA4F")
19 NEXTI
20 POKE2024,W


Posted By

Chicken
on 2009-01-12
17:23:37
 Re: Defining a custom charset from BASIC

Gaia...
When I clicked "POST" I thought "Well, maybe it was a joke after all!" :D No "edit option" here. Next time use "wink" so we know that you try being funny wink

Gerliczer...
I understand your point about the routine not being elegant, though, I totally agree with Csabo. It's a neat little routine that does what it's supposed to and doesn't need simulated keystrokes. The latter represents what I would not call elegant. For some projects (ab)using ROM routines is perfect. Well done happy

See, even if it comes late, it might be still of some use to someone. Many (in a plus/4-sceneish way wink ) of us came across those slow poke/peek code examples. And this is by far a better method.

I'm almost tempted to use it for something just to prove my point happy

Posted By

Chicken
on 2009-11-14
18:25:05
 Re: Defining a custom charset from BASIC

I just noticed that I never posted an example of the F1-key way I mentioned way above. Late, really not elegant but nevertheless a bit shorter then gerliczer's way wink


1 KEY1,"MONITOR"+CHR$(13)+"TD000 D7FF 3800"+CHR$(13)+"X"+CHR$(13)+"RUN3"+CHR$(13)
2 SYS56364:END
3 PRINT"HELLO PLUS/4 WORLD"


Of course "MONITOR" should be abbreviated by "M" and SHIFT+"O". Same for "RUN3": "R" and SHIFT+"U" and "3"

Also "cosmetic" stuff like switching off the screen (increases speed, too) should be added.



Back to topReply to this topic


Copyright © Plus/4 World Team, 2001-2024