Showing posts with label Motorola. Show all posts
Showing posts with label Motorola. Show all posts

Saturday, April 13, 2019

A 6809 Single Board Computer: The MC6839 Floating Point ROM



Implementing floating point math was a challenge with 8-bit microprocessors. The early version of BASIC for the 6502-based Apple 1 and Apple 2 series written by Steve Wozniak only supported 16-bit integer variables in order to keep the size down and achieve acceptable performance. Later, Applesoft BASIC was licensed from Microsoft which supported floating point variables. A significant amount of the code for Microsoft BASIC for 8-bit microprocessors was dedicated to floating point math. Some versions, loaded from tape, gave the user the option to leave out the sin/cos/tan trig functions to save space and free up some memory.

The 6809 supports instructions for 8-bit addition, subtraction, and division and some 16-bit math instructions. While more powerful than earlier processors like the 6502 and 6800, implementing floating point math was still a significant undertaking. Motorola saw an opportunity to offer a floating point math library as a standard product for the 6809. This was made more viable for two reasons:

  • An IEEE standard for floating point math formats appeared to be poised to become an industry standard.
  • The 6809 allowed writing position independent code, so a floating point library could be offered in binary form that would be independent of the memory map of the system it needed to run on.

Out of this came a product: the MC6839 Floating Point ROM. While essentially a software product, it was sold as hardware: an 8K ROM programmed with the floating point code. As well as the ROM, it included a programming manual almost 100 pages in length, describing how to use it.

The basic features of the library were:

  • An 8KB ROM which would run at any contiguous range of addresses.
  • All RAM used was relative to the stack pointer.
  • A well documented API that allowed operands to be passed in registers or via the stack.
  • Fully implemented the IEEE Standard for floating point math (at the time, still in draft form).
  • Support for the following operations: add, subtract, multiply, divide, remainder, square root, integer part, absolute value, negate, condition code compares, conversion between integer and floating point, and conversion between binary floating point and BCD.
  • Supported three precisions (4, 8, and 10 bytes) defined by the IEEE standard.
  • Supported the rounding modes, closure modes, and normalize modes defined by the standard.
  • Supported handling of exceptions (e.g. division by zero).

According to the source code it was written around 1980, with revisions up to at least 1982. The author names in the source code were Greg Stevens, Joel Boney, and G. Walker. In 1988 the source code was put in the public domain by Motorola, and can be found on the Internet as well as the binary for the ROM.

I came across the code and decided to try it out on my 6809 single board computer. There is a programming example in the manual that finds the roots to quadratic equations of the form ax^2 + bx +c = 0 using the classic formula -b +/- sqrt(b^2 - 4ac) / 2a

I typed in the example and adapted it to the lwasm assembler. The program uses a standard set of macro instructions to set up the parameters in the correct calling sequences for the ROM. These macros make the code much more readable and were easily ported to the lwasm assembler. I needed to make a few changes in order to make the example a complete runnable program. When run, and with the S record file for the MC6839 ROM also loaded into memory, I was able to get the example to run and produce the correct results. The code is on my github account.

Since I had the source, I took a look at whether I could assemble it. It would take some effort because the original source required a special Motorola "structured assembler" that I have not been able t find any information about. It has a number of structured programming macros for things like looping and conditionals. Given some time this could be reversed engineering by looking at the binary file.

I also found that the source does not quite match the binary (the former has a 1980 copyright date and the latter 1982). Without having a known good binary that corresponds to the source code, porting would be a challenge, so I set any further work on this aside for now.

The MC6839 Floating Point ROM was Motorola's first foray into this type of binary ROM product. The data sheet lists the product as "preliminary" and according to one source it was never actually offered as a product.

Later processors, like the 68000 series, would support floating point math in hardware using either a separate dedicated chip or on-board floating point unit (FPU). These still use (as do modern computers, including your smart phone) the IEEE standard for floating point math.

References

  1. https://github.com/jefftranter/6809/tree/master/sbc/mc6839
  2. http://github.com/brouhaha/fp09
  3. http://www.colorcomputerarchive.com/updates/2017
  4. http://www.classiccmp.org/pipermail/cctalk/2017-March/033678.html
  5. http://www.classiccmp.org/pipermail/cctech/2016-June/019519.html
  6. http://www.colorcomputerarchive.com/coco/Documents/Manuals/Hardware/MC6839%20Floating-point%20ROM%20Manual.pdf

Tuesday, February 5, 2019

A 6809 Single Board Computer: Disassembler and Thoughts on the 6809


As a project to use my 6809 SBC and learn more about 6809 assembly language programming, I wrote a disassembler that can run on the board. The design was loosely based on the one I did for the 6502.

While straightforward in principle, a disassembler for the 6809 is a little more challenging that for the 6502 for a number of reasons:
  • It supports many instructions.
  • Some instructions have unique operand formats (e.g. TFR/EXG, PSH/PULS).
  • There are many (24) different indexed addressing modes.
  • The instruction length can change based on the indexed addressing mode being used.
  • Some instructions are two bytes long, prefixed by $10 or $11 (the so-called page 2 and page 3 op codes).
Implementation was pretty straightforward. I used lookup tables for a number of things including op codes, instruction types, addressing modes, and mnemonics. I strove to make the code readable and avoided any tricks that might increase efficiency slightly at the expense of clarity.

It is mostly portable. It uses ASSIST09 monitor routines for i/o, but other than that could be used on other systems with minor changes.

I implemented over a few evenings, building it up in pieces. It took some time (but less than I expected) to handle all the index addressing modes and to correctly handle the differing instruction lengths and page 2/3 instructions.

My basic approaches for testing and debug were:
  1. Test low level functions, like PrintString, on their own with some test code.
  2. "Desk check" complex code on paper to try to verify the logic, use of registers, etc.
  3. Build it up in stages and confirm them working before adding on (e.g. initially just display hex bytes)
When I ran into bugs I used the "desk check" method as well as making use of breakpoints when running the code to see what it was doing at various steps. Having a working monitor to run, display and change memory and registers, etc. was a requirement and ASSIST09 worked well for that. Downloading new versions of code over the serial port only took a few seconds.

I initially ran it standalone, but at the end I was able to also support installing it as an external command in the ASSSIST09 monitor, so you can run it by typing U (for unassemble). ASSIST09 has calls to add new commands, so it can be done without changing the code in ROM.

Here is some sample output (disassembling the start of the ASSIST09 ROM code):

>U F800
F800  30 8D 68 BE  LEAX  $68BE ,PCR
F804  1F 10        TFR   X,D
F806  1F 8B        TFR   A,DP
F808  97 9D        STA   $9D 
F80A  33 84        LEAU  ,X
F80C  31 8C 35     LEAY  $35 ,PCR
F80F  EF 81        STU   ,X++
F811  C6 16        LDB   #$16 
F813  34 04        PSHS  B
F815  1F 20        TFR   Y,D
F817  E3 A1        ADDD  ,Y++
F819  ED 81        STD   ,X++
F81B  6A E4        DEC   ,S
F81D  26 F6        BNE   $F815 
F81F  C6 0D        LDB   #$0D 
F821  A6 A0        LDA   ,Y+
F823  A7 80        STA   ,X+
F825  5A           DECB
F826  26 F9        BNE   $F821 
F828  31 8D F7 D4  LEAY  $F7D4 ,PCR
F82C  8E 20 FE     LDX   #$20FE 
F82F  AC A1        CMPX  ,Y++
F831  26 02        BNE   $F835 
F833  AD A4        JSR   ,Y
PRESS SPACE TO CONTINUE, Q TO QUIT 

With a little more 6809 assembly language programming experience under my belt, it is interesting to compare it to the other 8-bit processor I am most familiar with, the 6502. Let me list a few thoughts here.

Having two accumulators is very handy. Often one is being used as an accumulator for some form of data, but another may be needed for indexing or as a parameter to calling another routine. Surprisingly, I also found myself using the 16-bit D register (which uses A and B) because I needed 16-bit data. Some functions, like addition and subtraction, are supported on the D register, but many only have 8-bit versions which you need to combine using several instructions to work on 16 bits of data.

Two index registers is also handy (the 6502 has two, but the 6809's predecessor the 6800 only had one). But I found in practice that I rarely needed a second one. Having 16-bit index registers, unlike the 8-bit registers of the 6502, was much more convenient as you often find you are using them to store addresses.

The 6502 typically makes the programmer heavily use addresses in the first 256 bytes of memory (page 0). Some key instructions and addressing modes can only work with page zero. For that reason, these tend to become valuable real estate and you can run out of them or run into collisions between different uses of them. In contrast, the 6809 has a more orthogonal instruction set and all relevant instructions can work with full 16-bit addresses. It does have direct mode (8-bit addresses) but with the Direct Page register you can have them work with any page of memory, not just page zero. I did not use this feature (the ASSIST09 monitor does) but I can see it being useful when you wanted to optimize the size of your code.

In general the 6809 is more orthogonal than the 6502, with few limitations on the addressing modes or operands of instructions. Unlike the 6502 you can push, pull, transfer, or exchange any registers. The push and pull (PSHS/PSHU/PULS/PULU) instructions are particularly nice in that you can push or pull a set of registers in one instruction. The order of push and pull is defined, so that you do not have to ensure that the order is correct in your code (provided you push and pull the same list of registers). There are two stack pointers, but I only used one. And of course, the 16-bit stack pointer is much more reasonable than the 8-bit stack on the 6502 that is fixed in page 1 of memory.

Transfer (TFR) and Exchange (EXG) are two other instructions which are very handy for moving registers around without any restrictions. The 6502 had some limitations on what registers you could transfer and had no equivalent to EXG.

The 6809 introduced a MULtiply instruction, which sounded at the time like a luxury for assembly language programmers. I actually used it in an early version of my disassembler program when I needed to multiply the offset to a table by 4 and get a 16-bit result. I felt it was overkill using a multiply to do this, and later did it using two shifts (you can easily implement a 16-bit shift of the D register using two instructions: ASLB, ROLA).

The 6809 has many more addressing modes than the 6502, with 24 variations of indexed addressing. I think it is unlikely that assembly language programmers would use the majority of these as just a few of them generally suffice. I suspect the original intention may have been to help support compilers of high-level languages that could use these.

One quirk with indexed addressing that could confuse programmers is that the 5, 8, and 16 b-t offset modes consider the offset to be signed. So, for example, the 5 bit offsets are not 0 to 31 but rather -16 to 15. If you have a lookup table of 256 elements, for example, and expect the 8-bit offset indexed addressing mode to access all of them starting from an offset of zero, you will be surprised when values of $80 and higher don't read the table entries you expected. I ran into this, and solved it by using 16-bit offset in this case.

One instruction that you could easily overlook is LEA (Load Effective Address). It might not seem particularly useful, essentially removing one level of indirection. In fact it is very useful, and is the key to a lot of efficient programming as it can make use of all of the indexed addressing modes and make code position independent.

The 6809 supports position independent code (PIC). The ASSIST09 monitor, for example, is fully position independent. It is not particularly hard to write PIC code, and I made some effort to try this in the disassembler. Mostly it is a matter of using branches rather than jumps and using the PCR (program counter relative) addressing mode when working with addresses. I did leave the memory locations in RAM used by the program at fixed addresses. One annoyance is that as code gets larger during development 8-bit branches often fail and need to be converted to long branches. Unlike some assemblers, the one I was using did not automatically select short or long branches as needed.

Overall, the 6809 is quite a pleasant processor to program, with more instructions, more and larger registers than the 6502. Of course, it is not really a fair comparison as it came a generation later and could make use of advanced in technology that allowed a more complex chip. The 6800 was of the same vintage as the 6502. In fact, the decision to use the 6502 over the 6800 in a number of early computers was based on cost. Compared to the $300 price tag of the 6800, the 6502 sold for $25. The Apple 1 was originally designed to use a 6800, but was converted to the 6502 when Steve Wozniak learned about it. The schematic diagram for the Apple 1 still listed the circuit changes needed on the board to use a 6800.

Sunday, July 9, 2017

Building a 68000 Single Board Computer - 6809 to 68000 Assembly Language Source Translator

Unlike Intel, which made a decision to keep a high level of compatibility in their x86 processor line, from the 8086 through 286, 386, 486, and Pentium and beyond, Motorola made a clean break when they introduced the 68000. It didn't offer any software compatibility with their earlier processors like the 6800 and 6809.

However, Motorola offered a tool to help programmers port their source code from the 6809 to 68000 microprocessor. The tool, written in Pascal, was intended to do about 90% of the work of translation.

I was able to find a copy of this tool at http://www.retro.co.za/68000/XLATE09/ and try it out. It includes the tool (both executable and source code), documentation, and some sample files.

I was able to run the original trans09.com executable under using the dosbox MS-DOS emulator. I was also able to run it under Windows 10, but I got a number of errors that I had to ignore.

The tool was written in Pascal. It didn't specify which compiler it was targetted at, but it looks like pretty standard Pascal. I was able to compile it using the Free Pascal compiler under Linux with the addition of one line: "Uses Crt;". I made a few other changes to remove warnings about unused variables. The data files used by the program also needed to be renamed to lower case as Linux is case sensitive.

The tool ran quite well, working as described. Much of the translation rules are contained in data files which can be modified. It also uses some small routines which need to be assembled separately.

M6809 to M68000 Source Code Translator     Version 1.2
Systems Engg, E. Kilbride, Scotland
Motorola Inc. Copyright 1986

   Code in       Code out         Errors         Warnings
      17             23              0               4

The basic approach is to map the 6809 registers to corresponding 68000 registers, e.g. A to D0, B to D1, D to D2, X to A0, and Y to A1. It converts 6809 instructions to corresponding 68000 versions, e.g. LDA to MOVE, and points out possible problem areas, like where the behavior of the overflow flag may be different. Some instructions cannot be converted at all. The intention is that this might do about 90% of the conversion and a programmer would need to do the rest.

Here is a sample conversion, first the 6809 code:

* Sample input program
NULL     EQU   0
         CMPA  #9
         BLS   CB1HX1           branch if number is 0-9
         ADDA  #7               number is 10-15 so add 7 to make it A-F

CB1HX1   ADDA  #'0              add the ASCII offset
         RTS

OP1HEX   PSHS   A               save the binary number
         BSR    CB1HEX          convert the number to its ASCII equivalent
         LBSR   OPCHAR          and output it to the system terminal
         PULS   A,PC            restore the binary number and exit
         EXG    A,B             save the l.s. ASCII character in B; original 8-bit number to A
         LSRA                   shift the m.s. half byte into the l.s half byte
         LSRA
         LSRA
         LSRA
         NOP
         RTS                    leave the m.s. ASCII character in A

And now the resulting 68000 version generated by the tool:

*++       ******   STUB EXTERNAL REFERENCES  ******

                  XREF ..DIN,..DOUT,..JSR,..RTS,..CTOX,..CREP
                  XREF ..DPR,..DPW,..CLRAB,..MUL,..INIT,..VREP
          
* Sample input program
NULL      EQU 0                 
          CMP.B #9,D0           
          BLS CB1HX1            branch if number is 0-9
          ADD.B  #7,D0          number is 10-15 so add 7 to make it A-F

CB1HX1    ADD.B  #'0',D0        add the ASCII offset
          BSR ..RTS              

OP1HEX    MOVEM.L D0,-(A6)      save the binary number
          BSR CB1HEX            convert the number to its ASCII equivalent
          BSR OPCHAR            and output it to the system terminal
          MOVEM.L (A6)+,D0      restore the binary number and exit
          MOVE.L (A6)+,A3       
          JMP (A3)              
          EXG.L  D0,D1          save the l.s. ASCII character in B; original 8-
*                               bit number to A
          LSR.B #1,D0           shift the m.s. half byte into the l.s half byte
** WARNING **                      * V-BIT CLEARED *
          LSR.B #1,D0            
** WARNING **                      * V-BIT CLEARED *
          LSR.B #1,D0            
** WARNING **                      * V-BIT CLEARED *
          LSR.B #1,D0            
** WARNING **                      * V-BIT CLEARED *
          NOP                    
          BSR ..RTS             leave the m.s. ASCII character in A

To actually use this tool you may need to modify it and/or the data files to work with your particular 68000 cross-assembler. For example, the VASM assembler I use does not like the stub routine names starting with two dots like "..RTS" but will accept them with only one dot (e.g. ".RTS").

I've put my test files and notes here: https://github.com/jefftranter/68000/tree/master/xlate09

I don't know if anyone used this tool to port any significant programs for the 6809 to 68000, but it is a rather interesting tool and the concept could be applicable to other processors. It is also an alternative approach to emulation, which is often use but has a different set of tradeoffs (like performance).