Following Day 7, I reached an important milestone in my exploration of C development on the Thomson MO5:
I finally had two fully functional tutorials.

They were still simple, but they were stable, reproducible, and understandable.

At that point, they relied on two very different approaches:

  • one tutorial using my home-made string, stdio, and ctype libraries
  • another tutorial based exclusively on cmoc.h

It was the right moment to step back and analyze what CMOC really provides.


Taking a closer look at cmoc.h

By examining cmoc.h more carefully, several observations became obvious.

String handling

All the functions I had implemented in my custom string library already existed in CMOC.

They were not only present, but correctly implemented and stable.

From that point on, maintaining a home-made string library no longer made much sense.


Standard input / output (stdio)

Here, the situation was more subtle.

Some important functions were missing, notably getchar().

This function was essential for me, because it allows simple interactions such as:

Press Y to continue

CMOC provides readline(), but it reads a full line and only stops when the user presses ENTER.

In terms of user experience, this is clearly less pleasant when you want to react to a single key press.


Character classification (ctype)

In this case, my home-made library still made sense.

CMOC only provides:

  • isupper()
  • islower()

Other functions (isdigit, isalpha, etc.) were still missing and useful in my programs.


Towards a hybrid approach

The conclusion was quite natural.

I did not want to reinvent the wheel, nor did I want to give up what CMOC already does correctly.

A hybrid approach therefore imposed itself:

  • use CMOC where it makes sense
  • complement it with custom implementations when necessary

At first, I thought about having my libraries include cmoc.h, and having programs include only my headers.

But since my string library had become useless, that idea quickly felt awkward.

The final solution was much simpler:

  • cmoc.h is included directly
  • only missing functions are provided by complementary libraries

Issues and points of attention encountered

As soon as I started writing slightly more ambitious programs, several important pitfalls appeared.

These are classic problems on 8-bit machines, but they are far from obvious today.


1. Display and the system monitor

The Thomson MO5 uses a BIOS-driven display state machine.
Some ASCII codes are interpreted as commands.

The newline secret

On the MO5:

  • \n (ASCII 10) moves the cursor down one line
  • it does not return to column 0

For a proper newline, you must also send:

  • \r (ASCII 13)

This is a very common source of misaligned output.


Timing issues

The MO5 display logic is sensitive to timing.

If output calls are chained too quickly (for example fputs() followed by mo5_newline()), the video processor may receive bytes during a scrolling operation.

Result:

  • technical glyphs
  • incoherent characters
  • corrupted display

Solution: always group the text and the newline in a single call, for example:

fputs(“Some text\n”);


2. Critical stack management

The Motorola 6809 has very limited memory, and by default the stack is extremely small.

Symptom

The program:

  • behaves randomly
  • crashes for no apparent reason
  • displays weird stuff on screen
  • or breaks as soon as you declare:

char buffer[25];

After several tests (compilation + running in DCMOTO), I identified that the problem came from this seemingly harmless declaration, and I did not understand why. Gemini came to my rescue by providing the explanation.


Cause

The stack grows downward in memory.

If it becomes too large, it overwrites:

  • system monitor variables
  • video memory

From that point on, the behavior becomes completely unpredictable.


Remedies

Increase the stack size in the Makefile:

–stack-space=512

Or use static for buffers (this is what I did):

static char buffer[30];

The variable is then placed in a fixed area of RAM.


3. Strings: the number one source of crashes

On 8-bit machines, string manipulation is the main cause of crashes.

The strcat() trap

Never do this:

strcat(dest, &ch);

strcat() expects a null-terminated string.

By passing the address of a single character, it will read memory until it randomly encounters a zero.


Safe alternative

int len = strlen(dest); dest[len] = ch; dest[len + 1] = ‘\0’;

Always explicitly close the string.


The null terminator

Every string construction or conversion function (for example itoa) must explicitly append a final \0.

Otherwise, functions like fputs() or puts() will never stop.


Conclusion

Day 8 marks the moment when things started to become concrete.

I was no longer just experimenting, but with:

  • functional examples
  • a better understanding of CMOC’s strengths and limitations
  • a very clear awareness of hardware constraints

This hybrid approach turned out to be a good compromise.

And above all, it forced me to think like an 8-bit developer, where every byte, every call, and every timing matters. With modern development tools, these kinds of reflexes are not natural. On a daily basis, I mostly develop .NET microservices, where code readability is the priority and memory footprint is rarely a concern. Here, it is a completely different world. But going back to fundamentals, with strong and explicit constraints, often does a lot of good 😉.

The code associated with this article is available here:
https://github.com/thlg057/mo5-tuto