Close

Working on Jeff's Combination ROM / W27E257 Tests & CMOC

A project log for HB6809 Homebrew computer

This is my 6809 Homebrew Computer

dave-collinsDave Collins 02/05/2023 at 19:360 Comments
Hel ord
it's not Hellorld... but so close

So it's been a while how about an update?

  I have been working towards a number of projects lately including a interesting series (i think) on the ZX81 that I am working on, as well as HBSound my 8 bits sound card similar to the Disney sound source (with a beefed up sample clock circuit).  I landed on trying to get CMOC fired up on the HB6809 to a state that I can start writing some faster code (using a c like compiler).  The best part of this hobby is that you can really get lost in the minutia of the varied areas of home brew computing.  This week was software; and like so many things I really threw myself into it.

Really putting your foot in it:

  So if its not obvious, I am an autodidact when it comes to hardware design.  I try to test everything and build safe functional circuits that are close to the lower speed designs of the 70's and 80's, but  a lot of this is experimentation and keeping a solid notebook of what I think is going on.   I believe what Ive built in the HBSound is just about the best design I have ever made. However, what I lacked at the end of the project was a really good way to test the sound card at speed.  Enhanced basic is not really fast enough to write the buffer and produce anything further than a 200hz tone, and I am a complete novice when it comes to 6809 assembly (I know just enough to be really dangerous).  I am however proficient in C, specifically the flavor or C that was kicking about in the early  90's on 16 and 32 bit CPU's.  I also know a fair bit of Pascal, as well as some 8080 assembly language.   There exists a c like cross compiler for the 6809, called CMOC, it's very similar to C, and produces .srec files with little issue for quick loading over serial. 

  I set out to get CMOC,  to produce working machine language that Assist09 can load.  In an effort to facilitate this I had to figure out how to re-direct a minimal amount of the standard library to support the ACIA at A000.  The manual for CMOC actually is fairly comprehensive and includes a section on doing specifically this.  Additionally ASSIST09 has a few system calls that allow for things like sending a character and reading from the terminal a snap:

*******************************************
* ASSIST09 MONITOR SWI FUNCTIONS
* THE FOLLOWING EQUATES DEFINE FUNCTIONS PROVIDED
* BY THE ASSIST09 MONITOR VIA THE SWI INSTRUCTION.
******************************************
INCHNP  EQU     0               ; INPUT CHAR IN A REG - NO PARITY
OUTCH   EQU     1               ; OUTPUT CHAR FROM A REG
PDATA1  EQU     2               ; OUTPUT STRING
PDATA   EQU     3               ; OUTPUT CR/LF THEN STRING
OUT2HS  EQU     4               ; OUTPUT TWO HEX AND SPACE
OUT4HS  EQU     5               ; OUTPUT FOUR HEX AND SPACE
PCRLF   EQU     6               ; OUTPUT CR/LF
SPACEF  EQU     7               ; OUTPUT A SPACE
MONITR  EQU     8               ; ENTER ASSIST09 MONITOR
VCTRSW  EQU     9               ; VECTOR EXAMINE/SWITCH
BRKPT   EQU     10              ; USER PROGRAM BREAKPOINT
PAUSE   EQU     11              ; TASK PAUSE FUNCTION
NUMFUN  EQU     11              ; NUMBER OF AVAILABLE FUNCTIONS

We can call these by simply entering a software interrupt followed by a byte describing the function we'd like to do (very similar to a BDOS/BIOS call in CP/M.)  Armed with this knowledge I set out to build a output routine for CMOC that would use some of these routines to see if I could get the terminal to output an obligatory "Hello, World!" program.

The obligatory "Hello, World!" program:

 Before I discovered the system calls in assist09 I found you could output characters to the terminal by simply writing to A001, the main issue with this is that this process requires either a programmable interrupt and a buffer to handle waiting for the appropriate time when the ACIA is ready for data to output --- OR a subroutine that scans and waits for the register in the ACIA to show that it is ready (by returning 0x2).  If you simply send the character data to the interface you will find it will drop characters (like the picture above in the lead in).

To build a custom output routine is simple in CMOC and they did a lot of the ground work as well as documenting it  in the manual.  here's what I came up with:

// ASSIST09 SYSTEM CALLS USED #define OUTCH     1       // sends a character to the terminal #define MONITR    8       // soft start ASSIST09

void
newOutputRoutine(void)
{ char ch; asm { pshs x,b // save regs swi handler uses them swi fcb OUTCH // system call to ASSIST09 puls b,x // put them back } } // call the monitor to soft start... void softStart(void) { asm { swi fcb MONITR // system call to ASSIST09 } }

  The soft start routine is not essential but is useful for returning to the monitor from the program termination. 

You can then tell CMOC to replace the existing output routine with:

// console redirect --- this is copy paste from CMOC Manual
    setConsoleOutHook(newOutputRoutine);

This needs to be called before you start  using things in the standard lib that use the character output routine.  But if you run the test program:

Sucsess!
Sucsess!

This worked well using the following to make the compiler produce files we can use, the command is simply to tell CMOC to build SREC as the output (this is the s19 file format similar to Intel hex).  Then we tell it to use the FLEX as a target.  FLEX is a good choice because it has similar output characteristics to the HB6809 (using a ACIA) and we can avoid issues with control codes specifically being mismanaged by the terminal.  If you are interested the reason is burred in the standard lib code for CMOC, but following the calls to send a printf we can see that for most of the targets the strings are sent untouched - with exception to the default target the Tandy COCO, and FLEX.   COCO takes the <LF> control code (sent by \n in a printf statement) and converts it to a <CR> ... but then when the COCO processes this it produces <CRLF>.  FLEX (and the HB6809 expect <CRLF> to make the line advance and the cursor to return.  To resolve this issue CMOC is hard coded to make the changes necessary so that when you write :

printf("Hello, World!\n");

The cursor will drop to the correct location on the next line in the terminal (or screen buffer in the case of the COCO.)   I haven't tried it but I believe the dragon behaves similarly.

TLDR; you compile and send code like this:

cmoc --srec --flex hb6809.c

and then at the assist09 prompt:

>L
 <begin ascii transmission from terminal sending the .srec file>

As the interrupt routines for serial communication are not added to the combo ROM (as of yet ... though this might be a moot point with a fast UART --- more on that later).  I still use Jeff's recommended ascii -xfr setup to send files over serial: 

ascii-xfr -l 200 -c 10 -s <filename>

This tells ascii-xfr to wait 200ms between lines, and 10ms between characters.   This transmits the file to the terminal and then when completed assist09 returns 00. You usually have to press enter.  After you have loaded the file, then you have to use the 'L' command from assist9 to load the code at the entry point.  If you've not specified it the default origin address in FLEX is 0x000 so you can load your program from memory by typing:

G 0 <---- Zero not an O

 If everything worked you should be greeted with the output of your program.  Additionally I had to use the soft start for the Monitor (call is MONITR)) ~ you can jump to the reset vector in the ROM (which for now is at a fixed point @ 0xF837) but if it moves due to changes your code will need to be updated, using a soft start in the ROM via a system call will manage the monitor location in ROM for you.

ROM  Changes:

In looking deeper at the ROM (to try to figure out how the system calls work) I uncovered a curious detail about the RAM allocation for the monitor A snip from the README.md for the combination ROM:

This is a variant of firmware that combines both Microsoft BASIC and
the ASSIST09 monitor into one ROM. It also includes my disassembler
which adds a new monitor U command and trace function which adds a new
monitor T command.

It comes up in ASSIST09. You can start BASIC by running "G C000".

Memory map (16K EPROM):

BASIC         $C000 - $E3FF (9K)
DISASSEMBLER  $E400 - $EFFF (3K)
TRACE         $F000 - $F8FF (2K)
ASSIST09      $F800 - $FFFF (2K)

RAM usage:

BASIC         $0000 - $0178
DISASSEMBLER  $6FD0 - $6FDC
TRACE         $6FE0 - $6FFC
ASSIST09      $7000 - $7051

 If you consider the space between 0-7000 as fair game for coding you are left with 28672 bytes of space.  I asked Jeff if he thought there was any reason that moving the allocations up the map to the top of the ram would be an issue, and he stated he didn't think it would be a problem.  I did a little more digging and determined that ASSIST09 uses approximately 81 bytes for variables in ram to operate (which we need to load and save programs and for the system calls.)  Additionally, the monitor racks this 81 bytes under the system page which is another 255 bytes.  this means we can start the ram space for the monitor at 0x7EAB (giving ourselves about 4 bytes of wiggle room to the end of the RAM encase the need for revisions arise.) This new location leaves us with  32427 bytes of ram between the bottom of the monitor reserved area and system page, and the bottom of ram.  If you'd like to not write over the trace program and disassembler's ram area its a bit tighter (at 32387).  The Basic stack and variable space also uses approx 376 bytes of memory at the bottom of the ram, which for reasons I'll explain shortly I'd like to not touch.  Bringing the total available space to the programmer after revisions to 32051 bytes of continuous memory that can be played with without breaking ASSIST09 or basic.

 I also did the math to relocate the work areas for the disassembler and the trace functions of the ROM what I came up with is the following:

BASIC         $0000 - $0178
DISASSEMBLER  $7E2A - $7E36
TRACE         $7E3A - $7E56
ASSIST09      $7EAB - $7F00 -- (below the 255 byte system page)
        
ASSIST09 requires an offset -7955 below its ROM location which is 
coded to line 8485 of the monitor source under variable RAMOFS.

The other two added functions are ORG statements at the beginning
segments.

Note: there is approximately a 4 byte pad between sections, this 
seemed smart and as Jeff had already done this it was easier to 
do the math for the calculated area moves.

 I will add the resulting changes to the github, along with a .hex file for both 16k and 32k ROMs if you would like to play with it.

Testing the design with a Winbond W27E257 and creating a new ROM image:

The 90's gave us a lot of neat / weird things, one of those things are the W27E257.  The W27E257 is a pin correct replacement for the Intel D27256 optical erasable EPROM, but using EEPROM technology.   Since its getting harder to find replacement the D27128 and typically you can use a D27256 as a direct replacement, as long as the top address line A14 found on pin27 is managed properly in the design.  In the schematics for the HB6809 pin 27 is tied high, and we can use the D27256, as a drop in replacement if we start the code for the ROM at 0x4000.  Since this is true, this also means the W27E257 is a valid part to swap in place.    Having a electrical erasable EPROM has a ton of benefits, the most beneficial of which is the ability to erase and write it electrically.  Additionally since these chips were used in LOADS of 386, 486 and Pentiums, its very easy to get these ROM chips off resellers for around 2 dollars from the usual sources electronics recycling companies use (ie. EBAY).   It is as simple as burning the ROM code to the EEPROM starting at 0x4000.  I've provided hex files that correspond to the correct offset, but if you are creating a new ROM from source.  You need to set the file start address C000, and the buffer start address 4000.

Compiling a new ROM from scratch is essentially using a specific version of as9:

as9 <assist09.asm> -l c s bin s19 cre now

The resulting compilation will yell about the comments in the assembly file, this is fairly normal and has to do with the age of the assembler. they can be safely ignored.

Converting the ROM code to a intel .HEX file, is recommended as buring the .bin to a rom appears to be fairly broken at least with the TL866 II.  The best way to do this is with srecord the best directions for it's use / installation are here but just encase you are merely interested in the command:

srec_cat <input.srec> -Motorola -o <output.hex> -Intel

 The resulting .hex file will start at 0000, but you will need to set the eeprom burner to read start address as C000, and if using a 32k EEPROM (or a actual D27256) you will need to set the buffer offset to 4000. ie C000 will need to be at the begining of the readable rom space when the rom is selected as it's address decode starts the beginning of the readable area of the rom at C000 in the decode space.

 What's next:

I have to finish writing up a test program for HBSound for starts, now that I have suitable tool chain for writing some faster code this seems like the next best thing.  I ordered parts for my upcoming terminal project which I will work on next.    I also designed an adapter board,  for expanding the rom space into the top expansion address range.  PCBWay has again offered to sponsor the prototyping for the EEPROM PCB's I expect these to come in the next few days perhaps by weeks end.  This will allow me to play around with expanding the combo rom to include SLOAD and SSAVE (*commands for saving and loading .srec over serial via basic *) as well as dropping to the monitor from basic.  Additionally I would like the rom to load straight into basic.  The advantage to this is then I can try to coax CMOC into using the floating point instructions from within enhanced basic just as they are for the COCO target.  This is all down the road from here but I am glad you joined me for the ride thus far.  If you are new to my projects thank you for taking the time to check out my mad hobby.

Discussions