|  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  ) 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  
  Anyway, I wish there'd be an elegant way to do this... there must be one  
  |   
 |  
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  )
 
 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  
  |   
 |  
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  
  |   
 |  
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  
  Gerliczer... Brilliant   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 cake  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" 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  
  |   
 |  
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  
  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      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    But maybe I should really write something is assembly    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  
 
 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 " " so we know that you try being funny  
  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  
  See, even if it comes late, it might be still of some use to someone. Many (in a plus/4-sceneish way   ) 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  
  |   
 |  
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  
 
  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.
  |   
 |  
  |   |   
  
 
 Copyright © Plus/4 World Team, 2001-2025. Support Plus/4 World on Patreon |