There are a few details which have been left out of the specification for
this task.
Does it require input validation?
Is the binary input pure binary, or is it BCD?
Shouldn't it go both ways, i.e. shouldn't we also have to convert ROMAN to
BINARY as well as BINARY to ROMAN?
What about the console I/O routine? Shouldn't there be some definition of
how it's to be used? Should it be a call with the I/O character simply held
in a register before/after the call?
How much memory is used can be defined in two ways. (a) the number of
bytes, and (b) how much contiguous memory must be present in order to allow
the code to be implemented. It requires 200 bytes of RAM is not a valid
statement if that RAM has to be scattered over a 32-KByte range. If your
claim is that your code runs in 200 bytes of memory, it must be runnable on
a computer having only 200 bytes of memory. If you can't figure out how to
build a 200-byte RAM, then perhaps it might be more appropriate to suggest
it requires only 256 bytes of RAM, which you can buy.
Was the processor in question available in 1983? As I recall, the 6809 was,
but there are some which weren't.
Now, for the more subjective aspects of the comparison, how was the code
initially generated? How long did it take to code the problem? How long
to debug it?
How is the 6809E relevant to the timing of the Z-80 and 6502?
These issues should be resolved, I think, before everyone takes off.
Dick
-----Original Message-----
From: Sean 'Captain Napalm' Conner <spc(a)armigeron.com>
To: Discussion re-collecting of classic computers
<classiccmp(a)u.washington.edu>
Date: Sunday, April 18, 1999 1:28 AM
Subject: Re: Program Challenge (was Re: z80 timing... 6502 timing)
My entry uses the MC6809E as used in the Color Computer Line from Tandy.
My general approach to this (as well as programming in general) is to avoid
the use of logic statements (comparisons/branches) and trying to use all
the
registers to their best possible use.
Static memory usage: 163 bytes
Dynamic memory: 16 bytes
Stack memory: 12 bytes
Minimum Cycles: 21
Maximum Cycles: 687
One digit:* 144
*Due to implementation, this can be 1, 10, 100 or 1,000.
Code ROMable: Yes
Data ROMable: Yes
Code is Re-entrant: Yes
Data is Re-entrant:* Yes
Undefined Opcodes: No
Undefined Behavior: No
*Does a separate copy of static memory need to be created
for each re-entrant copy? If this answer is `no', then
the data is re-entrant.
The main process is set up to avoid complicated logic, which leads to
both
speed loss and size bloat. To this end, I have a jump
table for each digit
to print (PTAB). The digits to be printed are stored in TABLE in decending
order, since that's the way I calculate the number (from largest to
smallest). I classifed the Roman numbers into two classes, ones and fives.
The `ones' class contains I, X, C and M. The `fives' class contains V, L
and D. There is another class, called `tens' which is a subclass from
`ones' (X, C and M). TABLE is set up such that for any grouping, [the
register] X points to the `ones' character, the previous character is the
`fives' character, and the one previous to that is the `tens' character.
The routines pointed to by PTAB should be relatively straight forward from
there.
The only other tricky part comes to actually calculating the values to
print. ROMSUB repeatedly subtracts a value from the value we passed in,
keeping track of the number of times we do a subtract. This value to
subtract is stored inline of the code and is pulled off from the stack.
The
actual return is stored on the stack, and is done by
`JMP [1,S]' (where the
top of the stack contains the count).
The calls to ROMSUB occur from RM1000, RM100, RM10 and RM1, and to get
there, we first store the address of RM1000 onto the stack, and in the main
loop, the first line of code `JSR [,S] calls RM1000. This returns with the
count on the top of the stack (and the address to RM1000 is still there)
where we then convert it to a Roman digit. Then we update the address to
RM1000 by 4, which then points it to RM100. We keep doing this, calling
RM10 and RM1. The last adjustment lands us in RMEXIT, which cleans up the
stack and returns to the calling program.
**************************************************
* ROMAN CONVERT BINARY VALUE TO ROMAN NUMERALS
*
*ENTRY D VALUE TO CONVERT
* Y DESTINATION OF AT MOST 16 BYTES
*EXIT D DESTROYED
* Y PRESERVED
* ALL OTHERS SAVED EXCEPT CC
***************************************************
ROMAN CMPD #3999 CHECK RANGES
BGT ROMERR
CMPD #0
BLE ROMERR
PSHS X,Y,U
LDX #RM1000
PSHS X
LDX #TABLE
ROM10 JSR [,S]
PSHS D
LDB 2,S
BEQ ROM20
ADDB 2,S
SUBB #2 TIME SHORTER THAN DECB/DECB
DECB INDEX INTO JUMP TABLE
LDU #PTAB
JSR [B,U]
ROM20 PULS D
LEAS 3,S REMOVE COUNT AND RETURN ADDRESS
LDU ,S ADJUST FOR NEXT ROUTINE
LEAU 4,U
STU ,S
LEAX 2,X INCREMENT TO NEXT CHARACTER
BRA ROM10 CONTINUE
ROMERR LDD #$2A00
STD ,Y MARK ERROR AND END OF STRING
RTS
RM1000 BSR ROMSUB
FDB 1000
RM100 BSR ROMSUB
FDB 100
RM10 BSR ROMSUB
FDB 10
RM1 BSR ROMSUB
FDB 1
RMEXIT LEAS 4,S
CLR ,Y
PULS X,Y,U,PC
ROMSUB PULS U
CLR ,-S
RS10 CMPD ,U
BLO RS20
SUBD ,U
INC ,S
BRA RS10
RS20 JMP [1,S] RETURN TO CALLER OF CALLER TO ROMSUB
TABLE FCC 'MDCLXVI'
PTAB FDB P1
FDB P2
FDB P3
FDB P4
FDB P5
FDB P6
FDB P7
FDB P8
FDB P9
***********************************************
* FOLLOWING ROUTINES HAVE THE FOLLOWING
* ENTRY B OFFSET INTO JUMP TABLE
* U JUMP TABLE
* X TABLE
* Y STRING TO STORE INTO
* EXIT A DESTORYED
* B DESTROYED
**********************************************
P3 LDA ,X LOAD FROM 1 TABLE
STA ,Y+ STORE CHARACTER
P2 LDA ,X
STA ,Y+
P1 LDA ,X
STA ,Y+
RTS
P4 LDA ,X
STA ,Y+
P5 LDA -1,X LOAD FROM 5 TABLE
STA ,Y+
RTS
P6
P7
P8 LDA -1,X
STA ,Y+
SUBB #10
JMP [B,U]
P9 LDA ,X
STA ,Y+
LDA -2,X LOAD FROM 10 TABLE
STA ,Y+
RTS
***********************************************
-spc (Eat and Enjoy ... )