6809 ASM: Exchanging data between Assembly code and the BASIC interpreter on the Olivetti Prodest PC 128 and the Thomson MO6 (Part 4)


Here is part 4 of this mini series of articles about sharing data between the SIMIV BASIC interpreter and the Motorola 6809 machine code on the Olivetti Prodest PC 128 and the Thomson MO6.

Disclaimer

The techniques, examples and concepts described in this series of articles are made for the Olivetti Prodest PC 128 and Thomson MO6 microcomputers. The methods described in the 1st and 2nd articles can be easily applied to the Thomson MO5 series, while the method described in this one is specific for the PC 128 and MO6 ( because the BASIC 1.0 does not support EXEC command with parameters). They can be converted for the TO7, TO8 and TO9 series, however, to keep the article’s size as small as possible, I did not add specific sections with the converted memory addresses for the TO7/TO8/TO9. If you want me to extend my articles for the TO7, TO8 and TO9 series, please let me know in the comments below, thanks!

Method 4: Passing multiple parameters via EXEC command

For this method we use the EXEC command that allows us to run an arbitrary machine code subroutine and also pass it a set of parameters.

What does EXEC exactly do? It “jumps” the execution to a specified memory location. The type of jump is a JSR  (Jump to SubRoutine) and so to return to the BASIC interpreter we need to use the RTS (ReTurn from Subroutine) instruction as usual.

If you’re using EXEC just to call your subroutine (so no parameters passed) then the syntax is:

EXEC subroutine-entrypoint-address

Where subroutine-entrypoint-address is a valid memory address, for example:

EXEC &H50F6

If you want to pass parameters via EXEC to your subroutine then you need to add them after the entry-point address in one of the two following ways:

EXEC entrypoint-address, par1, par2, par3

Or

EXEC entrypoint-address par1 par2 par3

We’ll see later which of these two ways has to be used in each specific case. Unfortunately you have to use the first OR the second method depending on how you retrieve parameters in your machine code. I remember that the original manual mentioned only the 1st method and I think this was an errata. At the time it took me 2 or 3 nights during a summer to debug this and find the 2nd “secret” way lol… good times! 😀

So, for example, to pass parameters using the first method:

EXEC &H50F6,A%

Please Note: EXEC with parameters list is not supported in BASIC 1.0. BASIC 1.0 supports only “EXEC entry-point-address” .

Internals of this method

Also for EXEC the BASIC interpreter expects us to behave in a certain way in our machine code, so it’s vital to understand each detail of what follows.

1. Don’t touch registers DP and S…

Like for USR method also when using EXEC you should treat DP and S with care.

If you really need to use DP and/or S then make absolutely sure to save them on the user stack at the beginning of your assembly code and restore them before giving back control to the BASIC interpreter (you have to restore them also before calling the subroutines explained at point 3!).

If you need to know how to deal with DP and S then please check my previous article here.

2. Terminate your machine code with RTS

As said previously EXEC executes a JSR so, again, your machine code subroutine must end its execution with an RTS instruction.

3. Follow the correct order

Retrieving parameters passed via EXEC is a “serialised” process. In other words, we have to “manually” retrieve one parameter after the other in series.

To retrieve each parameter, EXEC requires us to call special SIMIV BASIC machine code subroutines. Such subroutines have to be called in the right order or the whole operation will fail and you’ll get error messages from the BASIC interpreter.

$EFE6 – The first routine to call is at location $EFE6 (routine name is RESBAN). This routine prepares the BASIC to retrieve parameters that we may have passed after EXEC address. Please note that this routine does NOT retrieve any parameters, it only “initialises” the process of retrieving parameters. This routine must be called before any other in this list and it also has to be called again AFTER we call PTRGET routine (here below). This is because PTRGET commute the BANK to the one where the value of the parameter is stored.

$21C6 – Usually the next routine we should call is $21C6 (aka IFEND). This is because, if the user has forgotten to pass any parameters with EXEC, we can deal with the situation by avoiding the BASIC subroutine to stop execution and give us an error. IFEND basically checks if (in the BASIC line of EXEC command) we are at the END of the line (please note that with END here we mean: a) no parameters left, b) we reached the “:” symbol or c) we have reached the actual end of the line). If we are looping to retrieve a set of parameters I recommend to re-execute IFEND before proceeding with retrieving the next parameter in the list.

Each of the next 4 routines below are to retrieve a specific data-type. If you call one of them and the user has passed a different parameter’s data-type then the BASIC interpreter will stop execution and display a “Type Mismatch at line xx” error message, to inform you that you have used EXEC with the wrong parameter’s data-type.

$EFE9 (aka LITINT), this routine retrieves a signed integer type. LITINT  is a bit special compared to the other 3 here below, because in the case of LITINT register X will contain the value of the integer and not the address of the value (as it happens for all other methods below). Bare this in mind when using LITINT! LITINT copies the variable value in the register X, so when manipulating it you won’t change the original BASIC variable value.

$EFEC (aka LITADR), this routine retrieves an unsigned integer, the value’s address is placed in the register X (so to access it you need to use indirect or indexed addressing mode).

$EFEF (aka LITSGN), this routine retrieves a single precision type, the value’s address is placed in the CPU register X.

$EFF2 (aka LITSTR), this routine retrieves a string type. The string value’s address is placed in X while the string length is placed in register B.

The next two routines below are a bit of an exception to some of the previous rules in the list. They are also a bit more “general purpose” (aka they can be used to read any data-type instead of a specific one).

$EFF5 (aka FRMEVL), this routine behaves exactly like the USR method. So it will retrieve a parameter, put the value’s address in register X, register A will contain the type etc.

$EFF8 (aka PTRGET), this routine retrieves a pointer to a parameter. CPU register X will contain the parameter value’s address, register A will contain the memory BANK number where the value is stored and  the byte $6105 (in the commuted bank) should contain the type id (2,3,4 or 8) as we have seen previously for the USR method.

4. Document your API (Application Program Interface)

If a user uses extra parameters that you did not read in your machine code then when machine code returns to the BASIC interpreter it will start “interpreting” from what’s left in the EXEC line. In this case the BASIC interpreter will give an error message to the user “Syntax error at line xx”.

5. Commutable Memory

As for all the other methods explained in this series, if you’ve stored your machine code in commutable memory then make sure you have the RIGHT memory BANK selected BEFORE running EXEC instruction, otherwise most likely you’ll end up crashing your PC 128.

When you use EXEC with PARAMETERS (like in this article) then the machine code that retrieves parameters MUST reside in non-commutable memory. This because the subroutines described above will commute memory if required and that may cause problems.

For Beginners: Don’t worry, I am working on an article that will show you a way (and a full assembly template) to have part of your code in non-commutable memory and part in commutable memory. It will also provide you a full framework for error handling.

Be careful also if your machine code plays with interrupts. Routines that plays with interrupts also must be placed in non-commutable memory.

6. Error handling needs some thinking

If you use routines $EFEC, $EFEF, $EFF2, $EFF9, if you have specified a wrong type in the EXEC command, then the BASIC will display a “Type Mismatch” error.

If your routine needs parameters and you’ve forgotten to pass them via EXEC, then the BASIC will show just a “Syntax Error” message that may be confusing for the user.

If you are retrieving parameters using $EFF5 or $EFF8 and you’ve passed parameters to your machine code using a comma to separate them, then the BASIC will generate a “Syntax Error” message. This is another reason why that message may appear confusing for a user. Same happens if you are retrieving parameters using $EFEC, $EFEF, $EFF2, $EFF9 and you’ve passed them using a space to separate them.

If you pass the right data-type, the right number of parameters and use the right parameter separation, but the value in a parameter is wrong, you’ll have to handle that in your machine code. The BASIC interpreter cannot (obviously) help you in this case.

A practical example of use

The following code will define one machine code routine that will retrieve parameters as explained above.

BASIC code

100 REM Using USR functions to 
110 REM exchange data between
120 REM ASM and BASIC 
130 CLEAR ,,,&H5EFF
140 PRINT"Loading machine code..."
150 FBADDR(0)=&H5F05:FBADDR(1)=&H5F06:GOSUB 500
160 FUNC1=&H5F06
170 PRINT"Done."
180 PRINT"Test:"
190 A%=ASC("A")
200 PRINT CHR$(A%)
210 EXEC FUNC1,A%:PRINT
220 PRINT CHR$(A%)
230 END
500 REM Load machine code
510 I%=0:OPC%=0:RESTORE 600
520 FADDR=FBADDR(I%)
530 READ OPC%:IF OPC%>255 THEN I%=I%+1:IF I%>1 THEN RETURN ELSE GOTO 520
540 IF OPC%<=255 THEN POKE FADDR,OPC%:FADDR=FADDR+1
550 GOTO 530
600 ' Header:
610 DATA &H39,&H100
620 ' Library:
630 DATA &H7E,&H5F,&H09,&HBD,&HEF,&HE6,&HBD,&H21
640 DATA &HC6,&H27,&HF4,&HBD,&HEF,&HE9,&H1E,&H01
650 DATA &HC3,&H00,&H01,&H3F,&H02,&H39,&H00,&H00
800 DATA &H100

FBADDR(0) (Function Base ADDRess 0) represent the library header.

FBADDR(1) Is the entry-point to the first available function/subroutine (in our case FUNC1).

To make the code a bit more readable, at line 160, we store address $5F06 in the variable FUNC1, so we can use FUNC1 to call our function.

For beginners: This is also useful when we have to move the entry-point of the machine code for FUNC1, since all our BASIC code that calls it refers to the variable FUNC1 which will be easy to update in a single place in our code.

Lines from 180 to 230 are to demonstrate the usage of the method discussed in this article.

As usual lines from 500 to 550 are to load the machine code in the correct memory area.

Lines from 600 till the end are our actual machine code (basically pre-assembled for your convenience if you do not want to use the Assembler).

For beginners: Please don’t forget that the pre-assembled code is basically identical to the Assembly code below. The Assembly is easier to read so we’ll discuss what the machine code does using the Assembly source code.

ASM Code

00100         ORG     $5F00
00110 ***************************
00120 * Assembly Functions Lib 
00130 * for Motorola 6809 (PC128)
00140 * By Paolo Fabio Zaino
00150 ***************************
00160
00200 ***
00210 * Lib micro Header v0.2
00220 ***
00230         FCB     $00,$00,$00,$00,$00
00240 LIBR    RTS
00300 ***
00310 * Library entry points
00320 ***
00330 FUNC1   JMP     HFUNC1
00350 *FUNC2  JMP     HFUNC2
02000 *** 
02010 * User Functions Implementation
02020 ***
02030 ** FUNC1: Increment input parameter and print char
02040 HFUNC1  JSR     $EFE6
02050         JSR     $21C6
02060         BEQ     LIBR
02070         JSR     $EFE9
02080         EXG     D,X
02090         ADDD    #$01
02100         SWI     
02110         FCB     $02
02120         RTS     
09000 *
09010 * End of Library
09020         END     LIBR

So what does the ASM code above do?

Lines from 200 to 240 are the very basic Library Header. This time I called it v0.2 because I added a little more to it (described below).

Lines from 300 to 330 are the new little addition the the very basic header which is called entry-points TABLE. Basically from line 340 (for example FUNC1) we create a set of rows in memory which identifies a jump to the actual subroutine. The set of rows is then identified with their address and the JMP to the actual routine implementation. This is why it’s called entry-points table. Using this simple technique we avoid to have function’s entry-points address changing when we change the function implementation. In other words the entry point for FUNC1 will never change, even when you change its code or the code of other functions in your library. That is very handy and makes our life easier.

Lines from 2000 to 2120 are our FUNC1 implementation (the reason why I call it (H)FUNC1 is because I consider the code that read the parameters “the Header of a function”).

Let’s see in detail how HFUNC1 works:

  • At line 2040 we call $EFE6 subroutine, which will go back to the BASIC interpreter to set BANK and pointers ready to “keep reading” line 210 (in the BASIC code) from our machine code.
  • At line 2050 we call $21C6 subroutine. We do this to ask the BASIC interpreter to check if at line 210 (of the BASIC code) there are any parameters ready to be read. If there are no parameters then $21C6 subroutine will set the Z flag (in the register CC) when returning to our machine code.
  • At line 2060 we execute a BEQ (Branch on EQual) which branches to LIBR label if the Z flag is set (LIBR is an RTS so we return to the BASIC interpreter without doing anything). If instead, the user has passed at least one parameter then execution will proceed to line 2070.
  • At line 2070 we call $EFE9 subroutine, this subroutine expect us to have passed an integer (%), if we haven’t then execution will stop and the BASIC interpreter will give us an error message “Type Mismatch” otherwise $EFE9 will read the parameter for us and will put its value in the Register X.
  • At line 2080 (since we cannot do math operations on index registers like X) we execute EXG to swap the value in Register D with the value of register X. This way we do not loose the value in D and we’ll be able to modify the value previously loaded in X.
  • At line 2090 we do our usual adding of 1 to the value of our parameter (just to do something with it, as always for the sake of the explanation).
  • At line 2100 we call SWI instruction that will also read the next byte (line 2110) where we have put $02 so we’ll call the PUTCHAR routine from the monitor and we’ll print the corresponding ASCII character we have obtained from the manipulation we did at like 2090.
  • At line 2120 we return to the BASIC interpreter.

Executing the example code

If you run the BASIC code then it will show you:

Loading machine code...
Done.
Test:
A
B
A

The output line after “Test:” is a simple print of the character represented by A% ( in our case 65=A ).

The second output line shows our machine code that has correctly received the A% parameter and has done his job at incrementing the value by 1 and then printed the corresponding character (in our case B since we passed A, you can try with other characters assigned to A% and see what happens).

The 3rd output line shows that A% has not been modified, that is because we used $EFE9 subroutine which copies the value contained in A% into the register X.

Another test you can try at this point is remove the “,A%” parameter from line 210 in the BASIC code and run it again, this time our machine code will exit without doing anything.

More examples of use

Now that you are familiar with EXEC let’s see other examples of use, since the EXEC method is quite complex to grasp compared to the previous ones.

Code to replace in previous BASIC code

210 EXEC FUNC1 A% :PRINT

Please note the SPACE this time!

Please Note: Also routine $EFF5 (FRMEVL) requires parameters space separated from your machine code entry-point.

As a general rule $EFEC,$EFEF,$EFF2,$EFF9 need comma separated parameters, while $EFF8 and $EFF5 need space separated parameters.

600 ' Header:
610 DATA &H39,&H100
620 ' Library:
630 DATA &H7E,&H5F,&H09,&HBD,&HEF,&HE6,&HBD,&HEF
640 DATA &HE8,&HB7,&H5F,&H02,&H1E,&H01,&HFD,&H5F
650 DATA &H03,&H1E,&H01,&HEC,&H84,&HFD,&H5F,&H00
660 DATA &HC3,&H00,&H01,&H3F,&H02,&H39,&H00,&H00
670 DATA &H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00
800 DATA &H100

Code to replace in the previous ASM code (if you are using the Assembler):

02030 ** FUNC1: Increment input parameter and print char
02040 HFUNC1  JSR     $EFE6 * Prepare BASIC
02050         JSR     $21C6 * Check if ANY Pars
02060         BEQ     LIBR
02070         JSR     $EFF8 * Get first Par via PTRGET
02080         STA     $5F02 * Store Par BANK at $5F02
02090         EXG     D,X   * Store Par Addr at $5F03
02100         STD     $5F03
02110         EXG     D,X
02120         LDD     ,X    * Load Par value in D
02130         STD     $5F00 * Store Par value at $5F00/01
02140         ADDD    #$01  * Do something with the value
02150         SWI           * Print the result
02160         FCB     $02
02170         RTS           * Return to BASIC

For beginners: In the above code I added some useful bits for you to use to debug things around OR as an example of how you could store parameters values stored in a separate BANK into the reserved non-commutable memory so that then you could call your IFUNC1 stored in a separate BANK and be sure that it could read them fine.

Line 02080 stores the value of register A at location $5F02. When using PTRGET the register A will contain the BANK number of where the retrieved parameter value is stored, you can then check $5F02 when back to BASIC to verify which BANK was used.

Lines from 02090 to 02110 are used to store the Address of the parameter value fetched by PTRGET to locations $5F03, $5F04, you can check if the address is the same with what VARPTR tells you from the BASIC interpreter.

Line 02130 is used to store the VALUE of the parameter retrieved by our assembly after PTRGET was executed at location $5F00 and $5F01 (D is a 16bit register so will use 2 bytes).

Reading multiple parameters

Also when reading multiple parameters the workflow is not very consistent. So again follow the details:

If you use PTRGET routine

When you use PTRGET to retrieve a parameter, then, to retrieve the next one you have to execute again $EFE6, this because PTRGET switches the current BANK to the BANK that contains the previous parameter value, hence it may not be the same BANK for the new parameter you’re fetching and PTRGET doesn’t reset registers and BANK as required by the BASIC to read the next parameter from the BASIC source code.

So, in this case things should look something like:

02030 ** FUNC1: Increment input parameter and print char
02040 HFUNC1  JSR     $EFE6 * Prepare BASIC
02050         JSR     $21C6 * Check if Par1 exists
02060         BEQ     LIBR
02070         JSR     $EFF8 * Get Par1 via PTRGET

-- Do something with Par1 --

02200         JSR     $EFE6 * Prepare for Par2
02210         JSR     $21C6 * Check if Par2 has been provided
02220         BEQ     LIBR  
02230         JSR     $EFF8 * We have Par2 so retrieve it

-- Do something with Par2 -- 

02900         RTS           * Return to BASIC

If you use $EFEC, $EFEF, $EFF2, $EFF9 it will depends on the parameter you’ll fetch.

$EFF9 is the safest of them all to use because it copies the parameter value in the register X, while the other have pointers to the value so the bank switching can get in the way.

Mixing $EFEC, $EFEF, $EFF2, $EFF9 with PTRGET

As you probably can guess we have an extra level of madness here lol (joking), but yes if you mix up calling $EFEC for example and then PTRGET then also your EXEC syntax will need to be mixed up to something like:

EXEC addr,par1 par2, par3 etc...

So I generally do not recommend it for the mental sanity of the people who’ll have to use your library 😀

Observations about this method

This method is by far the most complex of all the 4 presented methods, however it’s also the most powerful and allows you to understand more how the SIMIV BASIC works internally. This type of approach will be also useful for you when you’ll learn how to extend BASIC commands.

Pros

  • EXEC entry-point-address, par 1, par2, par3… is very useful because it’s possible to pass multiple parameters keeping the BASIC syntax simple and straight forward.
  • No need for a pre-shared known location.
  • No need for a pre-shared known data-type.
  • Easier to be used by the user who’ll need to work with our libraries of machine-code.
  • Provides enough support for error handling.
  • Doesn’t have any limitation in the number of functions we can define in our library and how many parameters they requires.

Cons

  • Makes our machine code more complex to write.
  • Doesn’t have a consistent syntax between parameter reading subroutines (this is known to confuse the user).
  • Shares variables address in most cases which means we need to be more careful with how we modify data in our machine code in order to avoid compromising the BASIC interpreter.
  • It’s clearly the slowest method given all the extra code that is being executed. However, if you wan to have multiple parameters using method 2, then also that code will grow more in density.

Ok that’s it for now, thanks for reading and I hope you’ve found some useful information here. If you enjoyed this post, please don’t forget to support my blog by:

  • Visiting my on-line hacking and engineering merchandise shop on redbubble.com by clicking here
  • Or you can also make a donation with the PayPal link in the column on your right
  • Or share this article

If you like my articles and want to keep getting informed on new ones you can follow me on on of those 21st Century thingies called FacebookTwitterInstagram or Pinterest

And as always if you have any questions please feel free to use the comments section below.

Thank you! 🙂

What Next?

13 thoughts on “6809 ASM: Exchanging data between Assembly code and the BASIC interpreter on the Olivetti Prodest PC 128 and the Thomson MO6 (Part 4)

  1. Pingback: Exchanging data between Assembly code and the BASIC interpreter on the Olivetti Prodest PC 128 and the Thomson MO6 (Part 3) | Paolo Fabio Zaino's Blog

  2. Pingback: Exchanging data between Assembly code and the BASIC interpreter on the Olivetti Prodest PC 128 and the Thomson MO6 (Part 2) | Paolo Fabio Zaino's Blog

  3. Pingback: Exchanging data between Assembly code and the BASIC interpreter on the Olivetti Prodest PC 128 and the Thomson MO6 (Part 1) | Paolo Fabio Zaino's Blog

  4. Very good article Poalo.
    These days i have tryed these method, but with many difficult, and posting in French forum i have found the right way.
    I saw that these methos are divided in constant value parameter methods and variable parameter methods.
    Do you think is possible to manage constant or variable to the same parameter position ?
    Thanks for your job.
    Best regards.
    Dino Florenzi

    Like

    • Hi Dino,
      thanks as usual.

      I am not sure I understand your question this time…

      When you say “constant value parameter” do you mean something like a literal value (for ex 2 or 345 or “hello”)? If so then you could only use subroutines that COPY the value in a register OR you can use something like the 1st method I explained (which again copies values).

      The problem with a literal value is that it has no real address (beside the position in the source code) and so cannot be used via a pointer. PTRGET for example, uses register X like a pointer to a “data” memory location.

      Hope this helps, best regards,
      – Paolo

      Like

    • Dino,
      because you’ve shared my article on that french forum (thx and wp told me lol) I have noticed by chance the code you’ve shared there.

      Here are some thoughts:

      – The code you shared didn’t work inside a program because you’ve loaded your machine code at location &H6000. That location is also the location from where a program gets stored by the BASIC interpreter unless you have reserved it. more details on my article about memory management: https://paolozaino.wordpress.com/2018/02/15/memory-management-on-the-mo6-and-olivetti-prodest-pc-128/
      It worked when called outside of a program because when outside of a program then the BASIC interpreter stores your temporary code in the BANK 0 (non-commutable memory). I showed how this work in the other article about playing with commutable memory.

      – When you put your instructions in a program things started to get overwritten most likely.

      – In the series of articles I have written so far I always used the last CLEAR parameter that allows the user to reserve some memory in the non-commutable memory (aka BANK 0), however to reserve memory in the commutable area you need to use the second parameter and ALSO make sue you select the BANK before the clear instruction, so for example if you want to reserve in commutable memory from &H6000 on BANK 3 and also reserve &5F00 to &H5FFF in non commutable memory then you have to write something like:

      10 BANK 3:CLEAR ,&H6000,,&H5EFF

      The above code will reserve the whole BANK 3 (from &H6000 till the end of the bank at &H9FFF) in commutable memory for you machine code and the usual &H5F00 to &H5FFF in non-commutable memory (aka BANK 0). I’ll give a full example of how to write machine code that use something like this in a future article if you are interested.

      At this point the only thing left to do for you is to make sure to select BANK 3 before you load your binary code via LOADM and also remember to switch to BANK 3 every time you have to EXEC your code from BASIC. By my experience you should switch to BANK 3 just before running EXEC so something like:

      20 BANK 3:LOADM “MYPROG.BIN”

      30 BANK 3:EXEC &H6000

      Please note, I have NOT added parameters, the WHY is now clear from the article here. To retrieve parameters then your machine code MUST reside in the non-commutable area (aka BANK 0). You can write code that is partially in non-commutable and partially in commutable memory, however parameters retrieving must be done from non-commutable area.
      So parameter retrieving when using BANK 1 worked only outside of a program and that is for clear reasons at this point.

      Final recommendation, never forget to use CLEAR correctly because, otherwise, the SIMIV BASIC either overwrites your machine code somehow (by storing there some variable or source code) OR your machine code may overwrite some part of the BASIC buffers or code. In both cases bad stuff will happens 😀

      Hope this helps somehow!
      Best regards,
      – Paolo

      Like

      • thank you very much.
        Paolo.
        I ‘am waiting for your sprite article, another argument that i am working from many days.
        Best regards.
        Dino.

        Liked by 1 person

      • Sure, I’ll put it on the list of things to write about, all suggestions are always welcome! I am just trying to structure the material for the PC 128 in a way so that everyone interested can follow, no matter what their background is 🙂

        Like

  5. Nice article! Congrats.

    Side note: The following code
    02090 EXG D,X * Store Par Addr at $5F03
    02100 STD $5F03
    02110 EXG D,X
    Can be shortened to:
    STX $5F03

    Actualy some simple artithmetics (addition & subtraction of a constant or any accumulator A/B or D) can be done on the X register without swaping it with D via the LEAX insruction.

    For instance: LEAX 2,X adds 2 to X. Simlarly LEAX -1,X subtract 1 to X.

    And, cherry on the cake, LEAX sets the Z flag when the result is zero. Hence you can do a simple count-down loop using LEAX -1,X followed by BNE. Isn’t that great?

    sam.

    Like

    • Hi Samuel,
      thanks for your comment and sharing this old trick.

      The goal of this series of articles is NOT about optimizing 6809 code, which would result in something more difficult to understand for people starting now (I am sure you are well aware of this).
      The goal here is to allow anyone who has never coded in Assembly on the PC 128 (and the MO6 etc.) to learn it easily and have fun with these computers.

      However if you want me to add to my list of articles to write a series of posts about all the tricks I have learned through the years on optimizing 6809 code, if there is time, I’ll try to do that. The 6809 was a lot of fun for me when I was a kid! 🙂

      Cheers!

      Like

  6. Pingback: Exchanging data between Assembly code and the BASIC interpreter on the Olivetti Prodest PC 128 and the Thomson MO6 (Part 5) | Paolo Fabio Zaino's Blog

Leave a Reply or Ask a Question

This site uses Akismet to reduce spam. Learn how your comment data is processed.