Sunday, August 12, 2012
Replica 1 Quick Reference, Apple 1 on the Raspberry Pi, and the return of IMSAI
Earlier I made a one page reference of useful addresses for the Replica 1. I've extended that into a more comprehensive four page quick reference. You can download it from here. That directory also has some documents I wrote like a summary of the 65C02 and 65816 processors and some errata for Apple 1 manuals.
I recently got a Raspberry Pi board. This is a very small (credit card sized), low cost ($35) embedded desktop computer that can run Linux. For fun I compiled the POM1 Apple 1 Emulator on it. It ran quite well although it was a little slow on the Raspberry Pi's 600MHz ARM CPU. I've ordered a hardware expansion board for the Raspberry Pi called the Gertboard and plan to use if for some hardware experiments.
I've started playing with the Propeller CPU on the Replica 1. It is quite an amazing chip - 8 CPUs with shared memory, a built-in high level language interpreter as well as machine language, and hardware I/O ports. It can even generate video (which it does for the Replica 1). I'll have more to say here as I explore it further.
I'm looking forward to getting the Apple Cassette Interface when Briel computers starts shipping them. It sounds like big things are in store for Briel Computers. Vince Briel is planning to purchase the assets
of IMSAI computer. They were one of the first home computer manufacturers (along with Altair) and a portion of the company was still in business. He is hoping to restart a project they had to introduce a new replica of the original IMSAI 8080 computer.
Labels:
6502,
Apple 1,
IMSAI,
Propeller Chip,
Raspberry Pi,
Replica 1
Wednesday, August 8, 2012
Converting Between Floating Point and Human Readable Format
In my last post I mentioned 6502 code that can convert between ASCII and floating point formats that was written by Marvin L De Jong and published in the February and April 1981 issues of COMPUTE! magazine.
I've now entered it and ported it to the CC65 assembler to run on the Replica 1.
As often seems to be the case, there were a number of errors in the printed code, such as symbols that were never defined. The "#" sign was also not used to specify immediate addressing (this was apparently a coding convention that the author followed in all of his published code).
Fortunately it seemed that the generated machine code in the listing was correct, so in most cases I was able to use that as a reference to determine what the code should be.
I also had to combine the code in the first article with changes in the second one as there was no complete listing of the final software.
The code used some i/o routines for the AIM-65 machine so those needed to be be replaced with equivalents for the Replica 1.
After a couple of evenings of porting and testing I had the string to floating point and floating point to string functions working (De Jong refers to it as "BCD format" but it is really an ASCII string format). So, for example, I could now convert a string like "+6.02214E23" or "-1.2E-19" to floating point and back to ASCII. I then updated my little test/demo program to support calling the new routines.
The floating point format used by the De Jong code is a little different from the format used by the Woz code, but I was able to convert them easily enough.
The final result is the demo program which exercises all the functions. Here is an example run:
FLOATING POINT DEMONSTRATION PROGRAM
F - FIXED TO FLOATING POINT
P - FLOATING TO FIXED POINT
L - NATURAL LOG
N - COMMON LOG
E - EXPONENTIAL
A - FLOATING POINT ADD
S - FLOATING POINT SUBTRACT
M - FLOATING POINT MULTIPLY
D - FLOATING POINT DIVIDE
B - STRING TO FLOATING POINT
T - FLOATING POINT TO STRING
? - THIS HELP SCREEN
X - EXIT
SELECT A FUNCTION: B
STRING TO FLOATING POINT
ENTER FP STRING: 1234
FLOATING POINT IS: 8A 4D2000
SELECT A FUNCTION: T
FLOATING POINT TO STRING
ENTER EXPONENT AND MANTISSA: 8A 4D2000
FLOATING POINT IS: 1234
SELECT A FUNCTION: B
STRING TO FLOATING POINT
ENTER FP STRING: 6.02214E23
FLOATING POINT IS: CE 7F8616
SELECT A FUNCTION: T
FLOATING POINT TO STRING
ENTER EXPONENT AND MANTISSA: CE 7F8616
FLOATING POINT IS: 60221399.E16
With the facilities here you could implement a math program like a scientific calculator. I may do that at some point.
I learned a little about floating point code with this project. It also reminded me that back at the time this code was written there was no standard for representing floating point numbers. That was addressed by the IEEE Standard for Floating-Point Arithmetic (IEEE 754) and most modern CPU chips that have floating point hardware now support this standard, and language compilers typically support it in their run-time libraries. CPUs that lack floating point hardware typically emulate it in software, using code much like the 6502 code here, but more complex and typically written in C.
As usual, all of the code can be found here and you are welcome to use it.
Sunday, August 5, 2012
6502 Floating Point Routines
In the August 1976 issue of Dr. Dobb's Journal Steve Wozniak and Roy Rankin published a listing of floating point math routines for the 6502. The code is portable and provides routines for floating point add, subtract, multiply and divide as well as natural and common log and exponential functions and conversion between fixed and floating point. A version of this code was later included in the firmware for the Apple II.
The article in PDF and text format is available from 6502.org so I thought it would be fun to get it running on the Replica 1. I took the code and made a few small changes to get it to assemble under the CC65 assembler. I also included some later fixes that were published in Dr. Dobb's.
I then wrote an interactive program that allows the different functions to be executed. I did some minimal testing and all the routines seemed to be working quite well.
Here is a sample run of the program (input by the user is in bold):
FLOATING POINT DEMONSTRATION PROGRAM
F - FIXED TO FLOATING POINT
P - FLOATING TO FIXED POINT
L - NATURAL LOG
N - COMMON LOG
E - EXPONENTIAL
A - FLOATING POINT ADD
S - FLOATING POINT SUBTRACT
M - FLOATING POINT MULTIPLY
D - FLOATING POINT DIVIDE
? - THIS HELP SCREEN
X - EXIT
SELECT A FUNCTION: F
FIXED TO FLOATING POINT
ENTER 16-BIT HEX NUMBER: 0123
FLOATING POINT IS: 88 48C000
SELECT A FUNCTION: P
FLOATING TO FIXED POINT
ENTER EXPONENT AND MANTISSA: 88 48C000
FIXED POINT IS: 0123
SELECT A FUNCTION: F
FIXED TO FLOATING POINT
ENTER 16-BIT HEX NUMBER: 0456
FLOATING POINT IS: 8A 456000
SELECT A FUNCTION: M
FLOATING POINT MULTIPLY
ENTER EXPONENT AND MANTISSA: 88 48C000
ENTER EXPONENT AND MANTISSA: 8A 456000
RESULT IS: 92 4EDC20
SELECT A FUNCTION: P
FLOATING TO FIXED POINT
ENTER EXPONENT AND MANTISSA: 92 4EDC20
ERROR OCCURRED AT ADDRESS $1FE6
SELECT A FUNCTION: A
FLOATING POINT ADD
ENTER EXPONENT AND MANTISSA: 88 48C000
ENTER EXPONENT AND MANTISSA: 8A 456000
RESULT IS: 8A 579000
SELECT A FUNCTION: P
FLOATING TO FIXED POINT
ENTER EXPONENT AND MANTISSA: 8A 579000
FIXED POINT IS: 0579
SELECT A FUNCTION: X
This code could be used to write assembly language programs that need to do floating point math. One piece is missing though -- conversion between the floating point representation and one that can be input by a user or printed. This is usually done using Binary Coded Decimal (BCD).
A little research found a couple of articles by Marvin L De Jong in the February and April 1981 issues of COMPUTE! magazine that described BCD to floating point and floating point to BCD conversion routines. While the floating point format he used was slightly different from what was used in Woz's code, I'm hoping that I can adapt it. So that is my next little project.
All of the code can be found here on github.
Wednesday, August 1, 2012
Musing on Kit Building
I love building electronic kits, and there is a long tradition of kit building among people who tinker with electronics, including amateur radio operators, that goes back almost 100 years.
That tradition continues today with products like the replica computers offered by Briel Computers and amateur radio kits from companies like Elecraft.
Despite predictions that surface mount technology and the reduced emphasis on electricity and electronics in education would mean the demise of kits, the popularity of kit building has grown in the last ten years or so, as part of what is now often called the "maker" movement.
While kits have differing levels of complexity in terms of the number of parts involved and effort to assemble them, it seems to me that there are four fundamentally different levels of kit building.
Let me expound my theory, which I think is original if not particularly insightful.
Level 1: Assembling From Pre-built Components or Modules.
Kits at this level involve assembling pre-built components and mechanically connecting pieces together but doesn't involve any soldering, or if it does, just simple soldering of wires and connectors.
I've heard people talk about "building their own computer" and more often than not they mean building one at this level -- taking a commercial motherboard, case, and power supply, and connecting them together into a working computer.
Examples of this category include the pre-assembled Apple Replica 1, the Arduino embedded controller or the Elecraft K3 amateur radio transceiver.
| An Arduino Embedded Controller |
This can be a good way to get started in electronics and build up confidence before you are ready to pick up a soldering iron.
Level 2: Building a Commercial Kit
The next level involves assembly of a kit that requires soldering as well as mechanical assembly. You need to be able to solder competently and identify electronic components. You don't need to understand the circuit being built and don't need expensive test equipment although a Digital Multi Meter (DMM) is very useful.
The kit may include a professional case, power supply, etc. or may leave it up to the user to provide these.
The Heathkit company was the premiere source of kits of this type for many years and was renowned for the quality of its manuals and the professional look of the kits when assembled.
Briel Computers and many other companies offer similar kits of this type.
| An Assortment of Heathkit Equipment |
Level 3: Building From a Provided Design
The next step up is to take an electronic design, such as one described in a magazine or book article, or possibly as little as a schematic diagram, and realizing it as working device.
This involves finding and sourcing all the components, figuring out how to lay out the parts and deciding what construction technique to use (such as simple point to point wiring, a printed circuit board, or others such as "ugly" construction style).
This level offers more risks and challenges. There may be hidden gotchas in the design that will depend on the parts used or how it is assembled. There make even be errors in the design.
The builder needs to understand the circuit although not how all component values were determined. You may need more extensive test equipment such as an oscilloscope, signal generators, etc. in order to test and debug it. You may need tune or calibrate the circuit for proper operation.
This was how a lot of equipment was built by radio amateurs in the old days and still today. Circuits were often published in books like the Radio Amateur's Handbook or periodicals like QST magazine.
It is very rewarding as the end result is unique and there are often opportunities for making modifications.
An example from amateur radio is a transceiver (transmitter and receiver) called the the Ugly Weekender that was published in the amateur radio magazine QST in the 1980s. I built this unit using "ugly" construction on a bare copper board and built it into a case.
| My Version of The Ugly Weekender |
Level 4: Building Your Own Design
This is the ultimate level where you are no longer building a kit, but your own design.
You design the circuit yourself (possibly based on some existing design) and assemble it. To be successful you need to fully understand the circuit. You may even want to simulate the design using circuit simulation tools, or at least prototype key portions of it to verify the design.
This level of project can take months or more depending on the complexity and the time available to spend on it. It is the most risky but also the most rewarding if successful. If you succeed at this you've reached the "black belt" level.
A small example could be the RAM/EEPROM card I designed and built for the Apple Replica 1.
| Replica 1 RAM/EEPROM Card |
In summary, kit building can be categorized into the four levels I outlined. In practice there is often a grey area between the levels.
So the next time you work on a kit or electronic project, maybe you will ponder at what level you are and maybe consider moving your kit building prowess up to the next level.
Tuesday, July 31, 2012
A YUMmy New Game
I wanted to write another game for the Replica 1, and after considering a few alternatives, I decided to write a computer version of YUM, a game that is popular with our family.
The winner is the person scoring the most points at the end of the game. This version supports up to three players of which any can be human or computer players.
It would be a little frustrating to write in BASIC and tedious in assembler so I wrote it in C using the CC65 6502 compiler/assembler. This had the advantage that I could develop and test it on a desktop Linux system.
There is nothing particularly novel about the code. The computer players play a relatively good game based on some simple rules. The game could support more than three players by changing a compile-time constant -- the only limitation is that the screen size only conveniently fits a table of scores for three players.
Because it was intended to run on the Replica 1 it was kept small and efficient to run within the 32K memory limit and only use uppercase characters and fit on a 40x24 character screen.
The source is released under an Apache license. Both the source code and a binary that will run on a Replica 1system can be found at here.
If you want to run it on a real Apple 1 or similar, you will need to have just over 16K of RAM. With a little effort I could probably get the code size down a little to fit in 16K (the Replica 1 has 32K).
For my next Replica 1 project I am eagerly awaiting the Apple Cassette Interface kits that Vince Briel is offering. I expect to be one of the first beta testers for this, and I have a cassette tape player ready to go.
Saturday, July 21, 2012
Getting Info About the System
I recently added a few more features to JMON. The main one is a new iNfo command which displays information about the system it is running on. Here is sample output:
CPU TYPE: 65C02
CPU SPEED: 2.0 MHZ
RAM DETECTED FROM: $0000 TO $7FFF
NMI VECTOR: $0F00
RESET VECTOR: $FF00
IRQ/BRK VECTOR: $0100
ACI CARD: NOT PRESENT
CFFA1 CARD: NOT PRESENT
MULTI I/O CARD: PRESENT
BASIC ROM: PRESENT
KRUSADER ROM: PRESENT
WOZMON ROM: PRESENT
The way some of this information was generated is somewhat interesting. I'll explain a bit about how the code was implemented.
To determine the CPU type I used some code from the Western Design Center manual for the 65xx series processors. The code first distinguishes between 6502 and 65C02 processors by the behavior of the negative flag in decimal mode. The 65C02 fixed the behavior to make the flag valid (also V and C) while the 6502 did not. It then tries a 65816 instruction which will change the carry flag but is an unimplemented instruction and hence a NOP on the 65C02. From this it determines if it is running on a 6502, 65C02, or 65816 processor.
There are different manufacturers of 65C02. I don't know of any easy way to distinguish between a Rockwell and WDC 65C02. Thw only added instructions on the WDC are STP and WAI which both stop the CPU from running. They require either a reset or an interrupt to restart the CPU.
To find the range of RAM the code does the following. Starting from address zero, it in turn writes all ones, all zeroes, and alternating ones and zeroes to each memory location. If the same data is read back, it is considered RAM. The original data at the location is then written back to avoid corrupting what is in memory (namely, JMON). This is done until memory is found that cannot be written to and read back with the same data. I then stop, so the test only checks for contiguous RAM starting at zero.
A wrinkle is to avoid writing to the area of memory where the code itself is running since it would get corrupted in the middle of execution. I do this by avoiding testing the 256 byte page where the memory test code resides.
Next is the CPU speed. We want to determine the approximate clock speed of the CPU. But how, since we have no reference to actual time? The trick I used is to make use of a serial port, which is available when a Multi I/O board is present. If we send some characters out the serial port and see how many CPU cycles it takes, we can determine how fast the CPU is running since the serial port works at baud rates that are independent of the CPU clock speed. The code is calculated to give a value that is approximately the clock speed in megahertz to two significant figures.
For testing if certain ROMS are present, like the Krusader assembler, we can check the first few bytes for known data.
For expansion cards, like the CFFA1, they may have ID bytes in hardware (the CFFA1 does) or we can look at the hardware registers like the 6551 on the Multi I/O board and check for behavior of the registers, such as specific bits that can or can't be changed. I wrote tests for the cards that I have, the CFFA1 flash card, Multi I/O card, and ACI Apple Cassette Interface (the latter I don't yet have).
I tested the new info command with 6502, 65C02, and 65816 processors and 1 MHz and 2 MHz crystal oscillators. I also tested it on the POM1 emulator. A screenshot under POM1 is shown below.
![]() |
| Info Command Running on the POM1 Emulator |
With these changes I am running out of features to add to JMON so I am considering it to be feature complete and calling it version 1.0.
I noticed it recently exceeded 8K in size, so it no longer fits in a single 8K EPROM. I could reduce it to under 8K by disabling some features. The disassembler has some reasonably large tables (which the assembler also uses).
Saturday, July 14, 2012
JMON Trace Function
I've implemented one of the features missing from JMON, and one that I had been relying on Krusader's mini monitor for: an instruction trace function. This function allows you to single step through a program, see a disassembly of the current instruction, and see the values of the hardware registers. This feature is almost indispensable for debugging code. Krusader does this but I wanted to write my own.
I can think of at least three ways to single step code. One is a hardware solution. The Apple 1 manual actually shows a circuit that does this, and presumably Woz used this circuit to debug the Apple 1. This approach is very useful for bringing up new hardware that may not yet be working, but it is complex and expensive.
A second approach is the use the breakpoint instruction (BRK). By inserting a BRK instruction in code, when executed it can jump to the break vector which can run code which shows the current values of the registers. You can then replace the BRK with the original instruction and place a BRK at the next instruction, and continue execution. A disadvantage of this approach is that it only works for code in RAM and not ROM, since the program memory must be written to with the BRK instruction.
A third approach, and the one I used, is to look at the next instruction to be executed, copy it to a buffer, and execute it in place. The instruction can be followed by code that jumps back into the trace code in the monitor program. This approach has the advantage of working even for code that is in ROM.
To make this work there are a couple of wrinkles. Some instructions change the flow of control (e.g. JMP and JSR) and would jump out of the trace code. To trace these I simulate instead of execute them, doing the equivalent of what the instruction would do. For example. a JMP instruction just needs to update the value of the program counter. These special instructions are JMP, JSR, RTS, RTI, and BRK. Similar are the branch instructions. Initially I thought I would simulate these, looking at the CPU registers to determine whether the branch was taken or not. This would get a little complex as there are about 8 branch instructions to simulate, each checking a different condition. Instead I use a simpler approach that can use the same code for all branches. I execute the branch instruction in the buffer, but I adjust the branch destination so it jumps to a known location in the trace code. Whether the branch is taken or not, it stays under control of the trace code.
My trace function produces similar output to Krusader's mini monitor. You can set the register values use the Register command, including the Program Counter. The "." command traces/executes one instruction.
The breakpoint feature of JMON works in conjunction with this. If a breakpoint is hit, it updates the register values and you can single step as desired. You can also use the Go command to execute from the current program counter address.
It took a little work to get all of this correct for all instructions. It leveraged the previous work on the disassembler and mini assembler. For example, I needed to know the length of each instruction and this information was already available in tables used by the disassembler.
A sample session is shown below. Commands entered by the user are in bold. The actual trace commands "." are not echoed.
JMON MONITOR 0.99 BY JEFF TRANTER
? R
A-00 X-00 Y-00 S-0140 P-00 ........
0000 00 BRK
A-00 X-00 Y-00 S-0140 P-00 ........
PC-6000
? R
A-00 X-00 Y-B0 S-0140 P-00 ........
6000 EA NOP
A-Esc
? A-00 X-00 Y-B0 S-0140 P-30 ..-B....
6001 A9 01 LDA #$01
? A-01 X-00 Y-B0 S-0140 P-30 ..-B....
6003 A0 01 LDY #$01
? A-01 X-00 Y-01 S-0140 P-30 ..-B....
6005 A2 01 LDX #$01
? A-01 X-01 Y-01 S-0140 P-30 ..-B....
6007 08 PHP
? A-01 X-01 Y-01 S-013F P-30 ..-B....
6008 68 PLA
? A-30 X-01 Y-01 S-0140 P-30 ..-B....
6009 38 SEC
? A-30 X-01 Y-01 S-0140 P-31 ..-B...C
600A 18 CLC
? A-30 X-01 Y-01 S-0140 P-30 ..-B....
600B 69 01 ADC #$01
? A-31 X-01 Y-01 S-0140 P-30 ..-B....
600D F8 SED
? A-31 X-01 Y-01 S-0140 P-38 ..-BD...
600E 69 10 ADC #$10
? A-41 X-01 Y-01 S-0140 P-38 ..-BD...
6010 D8 CLD
? A-41 X-01 Y-01 S-0140 P-30 ..-B....
6011 4C 17 60 JMP $6017
? A-41 X-01 Y-01 S-0140 P-30 ..-B....
6017 20 15 60 JSR $6015
? A-41 X-01 Y-01 S-013E P-30 ..-B....
6015 EA NOP
? A-41 X-01 Y-01 S-013E P-30 ..-B....
6016 60 RTS
? A-41 X-01 Y-01 S-0140 P-30 ..-B....
601A A9 28 LDA #$28
?
As part of my testing I modified the code to stay in trace mode and ran the Woz monitor and Apple BASIC under the trace code. They executed correctly, although a little slower than normal.
The code supports 65C02 instructions without any extra coding except the BBR and BBS commands which would need some additional branch instruction support. Some 65816 instructions should work but the new instructions which change flow of control would fail and it doesn't understand the variable length of instructions depending on the CPU mode (but it would be quite straightforward to add).
This new trace function should prove useful for debugging future code I write. As always, the code can be found here.
Subscribe to:
Posts (Atom)
