[Project Log] Python on the 6502/C64, 8080, 6800, 6809 and AVR

I’ll have to look more into this FLEX Operating system but did find some games for it:

http://tanrunomad.com/swtpc-flex-games/

1 Like

In transcribing some code from the 6800 to the 6502, this snippet had no obvious direct translation:

 1DB7 B6 11CA	      [4] 04064	         ldaa   DumpAddr+1 ; Now compare upper nybble of low byte
 1DBA 84 F0		      [2] 04065	         anda   #$F0
 1DBC F6 11BF	      [4] 04066	         ldab   DumpEndAddr+1
 1DBF C4 F0		      [2] 04067	         andb   #$F0
 1DC1 11		      [2] 04068	         cba
 1DC2 26 06 (1DCA)    [4] 04069	         bne    DumpLineContinue

The 6502 has a single accumulator and there are no operations other than transfer allowed between it and the index registers. Rethinking the properties of numbers yielded this:

 0AF0 AD 02BC	      [4] 01498		lda	DumpAddr	; Now compare upper nybble of low byte
 0AF3 4D 02B7	      [4] 01499		eor	DumpEndAddr
 0AF6 29 F0		      [2] 01500		and	#$F0
 0AF8 D0 08 (0B02)  [2/4] 01501		bne	DumpLineContinue

Exclusive oring a number to itself results in zero.

@bill looks like Adafruit is getting in the game with CircuitPython.

Seems to be built on top of micropython.

It has been a long and painful slog, but my emulator finally implements both the officially documented and undocumented behaviors of 6502 decimal mode.

It passes the test program at http://6502.org/tutorials/decimal_mode.html

The code is ugly and the adc and sbc instructions are substantially slower in decimal mode. Thankfully, they are not used often.

2 Likes

When I was talking transcribing 6800 code to the 6502, one of them is the TSC Space Voyage game. It is now running though there are some bugs to chase down…

SpaceVoyage65

2 Likes

For Happy Programmer's Day, I worked on transcribing the Space Voyage game to the 8080; it is about one-half done. Then I will do it for the AVR so that it will run on an Arduino.

4 Likes

Space Voyage for the 8080 is now feature complete and is playable.

Several days were needed to chase down a rather obscure bug with the short and long range scans reporting different numbers of stars in a quadrant.

.			  00844	* Put Objects in Sector Map
.			  00845
.05D3 CE 00DC     [3] 00846	PUTINM   ldx    #SECMAP   ; Point to map
.05D6 BD 106B     [9] 00847	         jsr    RANDOM
.05D9 84 0F	      [2] 00848	         anda   #$F       ; Gen random position
.05DB 97 85	      [4] 00849	         staa   TSAVE1
.05DD BD 031A     [9] 00850	         jsr    FIXXRG    ; Find in map
.05E0 E6 00	      [5] 00851	         ldab   0,X
.05E2 BD 106B     [9] 00852	         jsr    RANDOM    ; Gen random X
.05E5 84 03	      [2] 00853	         anda   #3
.05E7 97 81	      [4] 00854	         staa   ASAVE
.05E9 27 05 (05F0)[4] 00855	         beq    PUTIN2
.05EB 56	      [2] 00856	PUTIN1   rorb             ; Find X position
.05EC 56	      [2] 00857	         rorb       ; AAA
.05ED 4A	      [2] 00858	         deca
.05EE 26 FB (05EB)[4] 00859	         bne    PUTIN1
.05F0 C5 03	      [2] 00860	PUTIN2   bitb   #3        ; Is position empty?
.05F2 26 DF (05D3)[4] 00861	         bne    PUTINM    ; If not, repeat
.05F4 DA 7E	      [3] 00862	         orab   MASK
.05F6 96 81	      [3] 00863	         ldaa   ASAVE
.05F8 27 05 (05FF)[4] 00864	         beq    PUTIN4
.05FA 59	      [2] 00865	PUTIN3   rolb       ; BBB       ; Put object in map
.05FB 59	      [2] 00866	         rolb
.05FC 4A	      [2] 00867	         deca
.05FD 26 FB (05FA)[4] 00868	         bne    PUTIN3
.05FF E7 00	      [6] 00869	PUTIN4   stab   0,X       ; Save it

The original code kept an important bit in the carry flag between points AAA and BBB. The or instruction of the 8080 clears the carry flag, losing that bit.

Also, the 8080 cannot set its condition codes according to the contents of a memory location without loading the byte into the accumulator. Even then, an additional operation is needed such as a compare, and or or which also wipes out the carry flag.


Transcribing to the AVR has been easier. It has 32 registers, half of which has the full power of an accumulator. The only major drawback so far has been the lack of a decimal adjust instruction which the original code uses in several places. So instead of a single instruction, a call to a subroutine is needed.

 0003AC					  00998	DAA:
 0003AC E070	      [1] 00999		ldi		R23,0		; Initially no correction factor
 						  01000
 0003AD F408=0003AF [1/2] 01001		brcc	DAA_NotUCarry	; The add overflowed the upper nybble?
 						  01002
 0003AE 6670	      [1] 01003		ori		R23,$60
 						  01004
 0003AF					  01005	DAA_NotUCarry:
 0003AF F40D=0003B1 [1/2] 01006		brhc	DAA_NotLCarry	; The add overflowed the lower nybble?
 						  01007
 0003B0 6076	      [1] 01008		ori		R23,$06
 						  01009
 0003B1					  01010	DAA_NotLCarry:
 0003B1 EA90	      [1] 01011		ldi		R25,$A0		; Upper nybble needs correction if over 9
 						  01012
 0003B2 2F86	      [1] 01013		mov		R24,R22		; Make a scratch copy
 						  01014
 0003B3 708F	      [1] 01015		andi	R24,$0F
 						  01016
 0003B4 308A	      [1] 01017		cpi		R24,$0A		; Check if lower nybble is out of range
 0003B5 F010=0003B8 [1/2] 01018		brcs	DAA_CheckUpper
 						  01019
 0003B6 6076	      [1] 01020		ori		R23,$06		; Correct out of range lower nybble
 						  01021
 0003B7 E990	      [1] 01022		ldi		R25,$90		; Upper nybble needs correction if over 8
 						  01023					;   with carry from lower nybble
 						  01024
 0003B8					  01025	DAA_CheckUpper:
 0003B8 2F86	      [1] 01026		mov		R24,R22		; Make a scratch copy
 						  01027
 0003B9 1789	      [1] 01028		cp		R24,R25		; Check if upper nybble is out of range
 0003BA F008=0003BC [1/2] 01029		brcs	DAA_Add
 						  01030
 0003BB 6670	      [1] 01031		ori		R23,$60		; Correct out of range upper nybble
 						  01032
 0003BC					  01033	DAA_Add:
 0003BC 0F67	      [1] 01034		add		R22,R23		; Do decimal adjust
 						  01035
 0003BD 9508	      [2] 01036		ret
3 Likes

I would love to see a port of this to the Commander X16

Is his goal to run C64 binaries unmodified?

The creator is local. Maybe David @dave can twist his arm to give a talk on it…

It is not compatible with the C64. See the FAQ

From what little I read, the tools generate .PRG files and he claims to support the KERNAL API. So if I build something for the C64, it should run if I do not assume anything about the hardware other than a 6502 processor and RAM in the usual place…

It is actually the 65c02 not the 6502. There are some differences in timing and new opcodes.

As painful as that may be sometimes, I am limiting myself to the NMOS 6502 instructions because those work on all 6502 family machines. I do nothing timing dependent.

1 Like

I just reacquainted myself with one of the more aggravating limitations of the AVR instruction set. Many processors limit relative branches to between -128 and +127; the AVR limit is -64 and +63.

The AVR addresses program memory (16-bit) using word rather than byte addresses, so the range in bytes is the same as many others, but AVR instructions take up one or two words so that is half the number of instructions.

Brian posted a video SWTPC 6800/6809 Computer Review and History https://www.youtube.com/watch?v=SATjR-MWHDM

1 Like

Interesting twist. As the AVR version started coming up, it gave drastically different results than the others. The game uses pseudo-random numbers so comparing the versions is difficult.

So I rigged the number generator to start with the same seed for now and discovered to my horror that all four versions differed!

I have never worked at software from this angle before, “port” the code and compare the results to this level of detail.

Some of you may have taken a comparative anatomy or comparative religion class before, but I know of no comparative processors class which goes into much detail. The closest was a microprocessors class which covered the Motorola 6800 for several weeks, then the Zilog Z80 for another several. The lab exercises involved writing several simple programs on both.

An enlightening exercise would be to get a program moderate in size and complexity for one and write equivalent code for another processor.

2 Likes

Hi…I am 44 and from Eastern Europe, so I experienced some of 8-bit computers in late 80’s as a teenager. I have never heard of 8-bit Apple nor S100 computers till few years ago when I started to discover US computers. And I like it much. I built most of the N8VEM boards, SCELBI 8H replica, Cosmac Elf 2000 and SBC6120+IOB6120+FP6120 by Spare Time Gizmos. I used to use CP/M on Z80 Sharp MZ-800 and play games on my friends’ ZX Spectrum, Atari 800XL or Commodore C64. The Sharp MZ-800 is still my favorite computer and there is quite a lot going on here around it. We created some interface replicas and there is Unicard emulating floppy, RAMdisk and Quick Disk interfaces, adding VGA and Ethernet to this old computer.

1 Like

If you are into replicas, you might be interested in this site: https://obsolescence.wixsite.com/obsolescence

I have some of his kits and they are great.

One of the bugs in the 6502 version of Space Voyage was not in its code but a couple of the obscure forms of the ADC instructions in my emulator was inadvertently ignoring the carry flag…

1 Like

That subroutine turns out to be flawed. A set carry flag when beginning the adjustment indicates that the preceding add overflowed the upper nybble. The carry flag needs to remain set after the adjustment even if adding the correction factor does not set the carry flag.

Edit: The updated code…

 000A24					  02159	DAA:
 000A24 E070	      [1] 02160		ldi		R23,0			; Initially no correction factor
 						  02161
 000A25 E0A0	      [1] 02162		ldi		R26,0			; Presume carry flag is clear
 						  02163
 000A26 F410=000A29 [1/2] 02164		brcc	DAA_NotUCarry	; The add overflowed the upper nybble?
 						  02165
 000A27 6670	      [1] 02166		ori		R23,$60			; Correct upper nybble
 						  02167
 000A28 95A3	      [1] 02168		inc		R26				; Remember original carry flag
 						  02169
 000A29					  02170	DAA_NotUCarry:
 000A29 F40D=000A2B [1/2] 02171		brhc	DAA_NotLCarry	; The add overflowed the lower nybble?
 						  02172
 000A2A 6076	      [1] 02173		ori		R23,$06			; Correct lower nybble
 						  02174
 000A2B					  02175	DAA_NotLCarry:
 000A2B EA90	      [1] 02176		ldi		R25,$A0			; Upper nybble needs correction if over 9
 						  02177
 000A2C 2F86	      [1] 02178		mov		R24,R22			; Make a scratch copy
 						  02179
 000A2D 708F	      [1] 02180		andi	R24,$0F
 						  02181
 000A2E 308A	      [1] 02182		cpi		R24,$0A			; Check if lower nybble is out of range
 000A2F F010=000A32 [1/2] 02183		brcs	DAA_CheckUpper
 						  02184
 000A30 6076	      [1] 02185		ori		R23,$06			; Correct out of range lower nybble
 						  02186
 000A31 E990	      [1] 02187		ldi		R25,$90			; Upper nybble needs correction if over 8
 						  02188								;   with carry from lower nybble
 						  02189
 000A32					  02190	DAA_CheckUpper:
 000A32 2F86	      [1] 02191		mov		R24,R22			; Make a scratch copy
 						  02192
 000A33 1789	      [1] 02193		cp		R24,R25			; Check if upper nybble is out of range
 000A34 F008=000A36 [1/2] 02194		brcs	DAA_Add
 						  02195
 000A35 6670	      [1] 02196		ori		R23,$60			; Correct out of range upper nybble
 						  02197
 000A36					  02198	DAA_Add:
 000A36 0F67	      [1] 02199		add		R22,R23			; Do decimal adjust
 						  02200
 000A37 F008=000A39 [1/2] 02201		brcs	DAA_Carry		; Done if carry set
 						  02202
 000A38 95A6	      [1] 02203		lsr		R26				; Restore original carry flag
 						  02204
 000A39					  02205	DAA_Carry:
 000A39 9508	      [2] 02206		ret
1 Like