This article pretty much confirms what I suspected, but the author explains it pretty well.
The only thing really missing is how the "magic number" was derived to minimize the error.
This is just speculation on my part, but I see two potential approaches.
The first would be to pick some mid point value that reduces the maximum error for any legal number (within the range of floating point numbers).
The second would be to pick a value that is the mid point for the most common values a program uses, thus minimizing the error for that program more than for any value.
The first would be easy to calculate, the 2nd would require a lot of number logging & crunching.
https://betterexplained.com/articles/understanding-quakes-fast-inverse-square-root/
My on again off again blog about whatever computer related hobby projects I happen to be working on at the moment.
Wednesday, August 26, 2020
Article: Understanding Quake's Fast Inverse Square Root
Monday, March 9, 2020
A little blast from my past
Back in the 80s I was a partner in and vice president of a software business called Designing Minds, Inc.
Here are a few of the programs we produced. All of these are based on my runtime library, as was the Talking Storybook series, yet I somehow didn't get my name on any of the Copyrights. Gee, why did I ever leave?
Link
I was also president, and a partner in an Amiga hardware company.
Here is one of the Amiga drives we made:
Link
Here are a few of the programs we produced. All of these are based on my runtime library, as was the Talking Storybook series, yet I somehow didn't get my name on any of the Copyrights. Gee, why did I ever leave?
Link
I was also president, and a partner in an Amiga hardware company.
Here is one of the Amiga drives we made:
Link
Monday, March 2, 2020
MC-10 Memory map
This is the MC-10 memory map copied from the service manual, but with a few minor changes.
The address decoding inside the MC-10 is "minimal", so the Keyboard/VDG I/O responds over a full 16K area, but internal address decoding can be disabled by external expansion devices.
Programmer's should only use the top of that address range to access that hardware.
The MC-10 only includes 4K of RAM internally, but hi-res 256x192 2 color (RG6), and 128x192 4 color (CG6) modes require 6K. The 6847 VDG's buss is isolated from the expansion connector on the back of the machine, and the top address line isn't even connected, so you can't just plug in a RAM expansion to use hi-res modes. The hardware mod was published in a CoCo magazine shortly after the machine was released, but I'll have to look up what magazine. (Color Computer Magazine maybe?)
Making matters worse, the ROM places BASIC system variables, and interrupt vectors in the upper part of the internal 4K of RAM, so to use hi-res graphics you need a new BASIC, or to disable the ROMs. I've been working on a new ROM, so this is trivial for emulators.
MC-10 Memory map from the service manual
Hex Address
C000 - FFFF 16K ROM (only upper 8K used)
9000 - BFFF 16K I/O Slot (Keyboard, VDG control, and sound)
4000 - 8FFF 16K RAM (4K - 20K used) (video starts at $4000)
0100 - 3FFF Not Used
0080 - 00FF RAM internal to the 6803
0015 - 007F Not Used
0014 RAM Control Register
0013 Not Used
0012 Not Used
0011 Not Used
0010 Not Used
000F Port 3 Control and Status Register
000E Input Capture Register (low byte)
000D Input Capture Register (high byte)
000C Output Compare Register (low byte)
000B Output Compare Register (high byte)
000A Counter (low byte)
0009 Counter (high byte)
0008 Timer Control and Status Register
0007 Not Used
0006 Not Used
0005 Not Used
0004 Not Used
0003 Miscellaneous I/O Data Register
0002 Keyboard Output Lines
0001 Data Direction Register for miscellaneous I/O
0000 Data Direction Register for keyboard lines
The address decoding inside the MC-10 is "minimal", so the Keyboard/VDG I/O responds over a full 16K area, but internal address decoding can be disabled by external expansion devices.
Programmer's should only use the top of that address range to access that hardware.
The MC-10 only includes 4K of RAM internally, but hi-res 256x192 2 color (RG6), and 128x192 4 color (CG6) modes require 6K. The 6847 VDG's buss is isolated from the expansion connector on the back of the machine, and the top address line isn't even connected, so you can't just plug in a RAM expansion to use hi-res modes. The hardware mod was published in a CoCo magazine shortly after the machine was released, but I'll have to look up what magazine. (Color Computer Magazine maybe?)
Making matters worse, the ROM places BASIC system variables, and interrupt vectors in the upper part of the internal 4K of RAM, so to use hi-res graphics you need a new BASIC, or to disable the ROMs. I've been working on a new ROM, so this is trivial for emulators.
MC-10 Memory map from the service manual
Hex Address
C000 - FFFF 16K ROM (only upper 8K used)
9000 - BFFF 16K I/O Slot (Keyboard, VDG control, and sound)
4000 - 8FFF 16K RAM (4K - 20K used) (video starts at $4000)
0100 - 3FFF Not Used
0080 - 00FF RAM internal to the 6803
0015 - 007F Not Used
0014 RAM Control Register
0013 Not Used
0012 Not Used
0011 Not Used
0010 Not Used
000F Port 3 Control and Status Register
000E Input Capture Register (low byte)
000D Input Capture Register (high byte)
000C Output Compare Register (low byte)
000B Output Compare Register (high byte)
000A Counter (low byte)
0009 Counter (high byte)
0008 Timer Control and Status Register
0007 Not Used
0006 Not Used
0005 Not Used
0004 Not Used
0003 Miscellaneous I/O Data Register
0002 Keyboard Output Lines
0001 Data Direction Register for miscellaneous I/O
0000 Data Direction Register for keyboard lines
Nearing completion of the 6502 to 6803 AGD runtime code
As the title indicates, the runtime library code is almost complete. If I had just focused on working on the translation, this would have been done some time ago. but I hope to finish this today. Then I can look at the compiler.
There are some questions with the code that will require looking at the original Z80 code. Why did they do this, why didn't they do that... not sure if the 6502 programmer lacked experience, if I have outdated code, or whatever, there's just some odd looking stuff in the code.
There are sure to be some mistakes in the translation. At the very least, the Z80 & 6502 store 16 bit variables in little endian format, and the 6803 uses big endian. I'm assuming big endian for the translation, which may cause some problems. There may also be a few times where I tried to optimize the code, and I shouldn't have. Likewise, there's probably room for more optimizations where I wasn't sure if they are okay.
Before anyone gets too excited, just remember this requires the internal RAM mod that lets you use hi-res RG6 mode (PMODE 4), and a new ROM or external RAM expansion that lets you disable the internal ROM. The only RAM expansion that lets you disable the ROM is the MCX-128, but I'm not sure that has a memory map setting compatible with the internal RAM upgrade. This should work with an emulator though, and we can worry about the hardware issues later.
There are some questions with the code that will require looking at the original Z80 code. Why did they do this, why didn't they do that... not sure if the 6502 programmer lacked experience, if I have outdated code, or whatever, there's just some odd looking stuff in the code.
There are sure to be some mistakes in the translation. At the very least, the Z80 & 6502 store 16 bit variables in little endian format, and the 6803 uses big endian. I'm assuming big endian for the translation, which may cause some problems. There may also be a few times where I tried to optimize the code, and I shouldn't have. Likewise, there's probably room for more optimizations where I wasn't sure if they are okay.
Before anyone gets too excited, just remember this requires the internal RAM mod that lets you use hi-res RG6 mode (PMODE 4), and a new ROM or external RAM expansion that lets you disable the internal ROM. The only RAM expansion that lets you disable the ROM is the MCX-128, but I'm not sure that has a memory map setting compatible with the internal RAM upgrade. This should work with an emulator though, and we can worry about the hardware issues later.
Saturday, February 29, 2020
code update
The egregious 6502 vs 6803 code comparison has been updated. Yup, I was tired. The 6803 code should be okay now. While fixing the 6803 code, I also noticed the 6502 code looked like it could be improved.
The 6502 code from the shrapnel routine looks like it can be optimized as shown below. Instead of incrementing z80_hl for every byte, use different y offsets, and then update z80_hl once. The comparison is a little less lopsided with this change.
;----------------------------------------------------
; Explosion shrapnel.
;----------------------------------------------------
shrap:
ldy #1
lda (z80_ix),y ; get the angle.
clc
adc #<shrsin ; shrapnel sine table.
sta z80_l
lda #>shrsin
adc #0
sta z80_h
ldy #0
lda (z80_hl),y ; fetch value from table.
sta z80_e
iny ;#1
lda (z80_hl),y ; fetch value from table.
sta z80_d
iny ;#2
lda (z80_hl),y ; fetch value from table.
sta z80_c
iny ;#3
lda (z80_hl),y ; fetch value from table.
sta z80_b
lda z80_l ; add 4 to hl to advance pointer
clc
adc #4
sta z80_l
bcc :+
inc z80_h
:
ldy #2
lda (z80_ix),y ; y coordinate in hl.
clc
adc z80_c ; add cosine lb
sta (z80_ix),y ; store new coordinate lb.
iny
lda (z80_ix),y
adc z80_b ; add cosine lb
sta (z80_ix),y ; store new coordinate hb.
...
The 6502 code from the shrapnel routine looks like it can be optimized as shown below. Instead of incrementing z80_hl for every byte, use different y offsets, and then update z80_hl once. The comparison is a little less lopsided with this change.
;----------------------------------------------------
; Explosion shrapnel.
;----------------------------------------------------
shrap:
ldy #1
lda (z80_ix),y ; get the angle.
clc
adc #<shrsin ; shrapnel sine table.
sta z80_l
lda #>shrsin
adc #0
sta z80_h
ldy #0
lda (z80_hl),y ; fetch value from table.
sta z80_e
iny ;#1
lda (z80_hl),y ; fetch value from table.
sta z80_d
iny ;#2
lda (z80_hl),y ; fetch value from table.
sta z80_c
iny ;#3
lda (z80_hl),y ; fetch value from table.
sta z80_b
lda z80_l ; add 4 to hl to advance pointer
clc
adc #4
sta z80_l
bcc :+
inc z80_h
:
ldy #2
lda (z80_ix),y ; y coordinate in hl.
clc
adc z80_c ; add cosine lb
sta (z80_ix),y ; store new coordinate lb.
iny
lda (z80_ix),y
adc z80_b ; add cosine lb
sta (z80_ix),y ; store new coordinate hb.
...
AGD porting notes (what is required to port AGD to a new system)
When asked if there is a guide to porting AGD to a new system, this was Kees van Oss's response on facebook:
Not really ... but this is how MPAGD works and what needs to be done to port it:
1. You start with an ASCII AGD file with commands to define graphics and the game behaviour. This AGD file can be created by converting an existing AGD4.7 game or create one with AGDX Studio or Jonathan Cauldwells WinAGD program.
2. The next step is to compile this ASCII AGD file into an assembler source file. The compiler converts all ASCII AGD commands into assembler code and adds the engine to the assembler sourcefile.
The engine is a library with routines which are called by the assembler code linked to the AGD commands.
3. After compiling, you need to assemble the assembler file into a binary file ready to run on the designed system. This assembler creates a tape or diskfile which can be used by the emulator.
4. After creating the tape or disk files, an emulator is called with the created tape or diskfile to test the game. So what needs to be changed to port MPAGD are:
- The converter, a C program (Step 1)
- The compiler, a C program (Step 2)
- The engine, a Z80 assembler file (Step 2)
You can use an existing assembler and emulator program to complete steps 3 and 4.
Things that need to be defined for a platform are:
- memory map definition
- screen handling
- sound handling
- keyboard handling
All blocks, sprites and objects are software handled by peeking and poking into screen memory so there is no hardware sprite handling except the MSX port which handles hardware sprites. The screen is based upon the ZX Spectrum, 256x192 pixels. The Spectrum has 16 colours with the limitation of a 8x8 block with 2 colours
- Blocks (tiles) are 8x8 pixels, max 255
- Sprites are 16x16 pixels, max 12
- Objects are 16x16 pixels, max 255
All these specs can be changed but all AGD4.7 games are based upon these specs.
Are you planning to port MPAGD to another platform because we have a Developers environment where you can discuss your porting problems.
Not really ... but this is how MPAGD works and what needs to be done to port it:
1. You start with an ASCII AGD file with commands to define graphics and the game behaviour. This AGD file can be created by converting an existing AGD4.7 game or create one with AGDX Studio or Jonathan Cauldwells WinAGD program.
2. The next step is to compile this ASCII AGD file into an assembler source file. The compiler converts all ASCII AGD commands into assembler code and adds the engine to the assembler sourcefile.
The engine is a library with routines which are called by the assembler code linked to the AGD commands.
3. After compiling, you need to assemble the assembler file into a binary file ready to run on the designed system. This assembler creates a tape or diskfile which can be used by the emulator.
4. After creating the tape or disk files, an emulator is called with the created tape or diskfile to test the game. So what needs to be changed to port MPAGD are:
- The converter, a C program (Step 1)
- The compiler, a C program (Step 2)
- The engine, a Z80 assembler file (Step 2)
You can use an existing assembler and emulator program to complete steps 3 and 4.
Things that need to be defined for a platform are:
- memory map definition
- screen handling
- sound handling
- keyboard handling
All blocks, sprites and objects are software handled by peeking and poking into screen memory so there is no hardware sprite handling except the MSX port which handles hardware sprites. The screen is based upon the ZX Spectrum, 256x192 pixels. The Spectrum has 16 colours with the limitation of a 8x8 block with 2 colours
- Blocks (tiles) are 8x8 pixels, max 255
- Sprites are 16x16 pixels, max 12
- Objects are 16x16 pixels, max 255
All these specs can be changed but all AGD4.7 games are based upon these specs.
Are you planning to port MPAGD to another platform because we have a Developers environment where you can discuss your porting problems.
Thursday, February 27, 2020
several thousand lines later...
A lot of progress has been made, but... is it a bad thing for a game engine not to call functions like "shoot"? I have a feeling I'll be looking at the original Z80 code. On the bright side, I'm nearing the half way point converting the code.
The engine would be faster if the data structures stored X, and Y coordinates next to each other. But I can't fix that since the game design tool would need rewritten.
The engine would be faster if the data structures stored X, and Y coordinates next to each other. But I can't fix that since the game design tool would need rewritten.
Wednesday, February 26, 2020
... and another
This is a particularly egregious subroutine for the 6502.
I'm tired, so I'll have to double check the code later, but the 6502's 48 instructions are reduced to just 19 on the 6803.
The 16 bit X index register, 16 bit D register, and not having to write the contents of HL until we need to change X makes a huge difference. The 6502 has to store pointers on the direct page, and they are updated a byte at a time. The 65816 supports 16 bits, so it should be more like the 6803 here. The mode switching between 8 & 16 bit registers that can kill it's performance shouldn't be much of an issue.
;----------------------------------------------------
; Explosion shrapnel.
;----------------------------------------------------
shrap:
; ldy #1
; lda (z80_ix),y ; get the angle.
; clc
; adc #<shrsin ; shrapnel sine table.
; sta z80_l
; lda #>shrsin
; adc #0
; sta z80_h
ldx z80_ix
ldab 1,x ; get the angle
ldx #shrsin ; shrapnel sign table
abx ; X now contains z80_hl
; ldy #0
; lda (z80_hl),y ; fetch value from table.
; sta z80_e
; inc z80_l ; next byte of table.
; bne :+
; inc z80_h
;:
; ldy #0
; lda (z80_hl),y ; fetch value from table.
; sta z80_d
; inc z80_l ; next byte of table.
; bne :+
; inc z80_h
;:
; ldy #0
; lda (z80_hl),y ; fetch value from table.
; sta z80_c
; inc z80_l ; next byte of table.
; bne :+
; inc z80_h
;:
;
; ldy #0
; lda (z80_hl),y ; fetch value from table.
; sta z80_b
ldd 2,x ; fetch value from table
std z80_bc
;order changed because we use de below
ldd ,x ; fetch value from table
std z80_de
stx z80_hl ; still need to add 4 to hl, wait until done with de
; ldy #2
; lda (z80_ix),y ; x coordinate in hl.
; clc
; adc z80_e ; add sine lb
; sta (z80_ix),y ; store new coordinate lb.
; ldy #3
; lda (z80_ix),y
; adc z80_d ; add sine hb
; sta (z80_ix),y ; store new coordinate hb.
ldx z80_ix
; D still contains z80_de
add 2,x ; x coordinate,
std 2,x ; store new coordinate
; ldy #4
; lda (z80_ix),y ; y coordinate in hl.
; clc
; adc z80_c ; add cosine lb
; sta (z80_ix),y ; store new coordinate lb.
; ldy #5
; lda (z80_ix),y
; adc z80_b ; add cosine lb
; sta (z80_ix),y ; store new coordinate hb.
ldd 4,x ; y coordinate
add z80_bc ; add cosine
std 4,x ; store new coordinate
ldd z80_hl ; add 4 to hl
addd #4
std z80_hl
rts
I'm tired, so I'll have to double check the code later, but the 6502's 48 instructions are reduced to just 19 on the 6803.
The 16 bit X index register, 16 bit D register, and not having to write the contents of HL until we need to change X makes a huge difference. The 6502 has to store pointers on the direct page, and they are updated a byte at a time. The 65816 supports 16 bits, so it should be more like the 6803 here. The mode switching between 8 & 16 bit registers that can kill it's performance shouldn't be much of an issue.
;----------------------------------------------------
; Explosion shrapnel.
;----------------------------------------------------
shrap:
; ldy #1
; lda (z80_ix),y ; get the angle.
; clc
; adc #<shrsin ; shrapnel sine table.
; sta z80_l
; lda #>shrsin
; adc #0
; sta z80_h
ldx z80_ix
ldab 1,x ; get the angle
ldx #shrsin ; shrapnel sign table
abx ; X now contains z80_hl
; ldy #0
; lda (z80_hl),y ; fetch value from table.
; sta z80_e
; inc z80_l ; next byte of table.
; bne :+
; inc z80_h
;:
; ldy #0
; lda (z80_hl),y ; fetch value from table.
; sta z80_d
; inc z80_l ; next byte of table.
; bne :+
; inc z80_h
;:
; ldy #0
; lda (z80_hl),y ; fetch value from table.
; sta z80_c
; inc z80_l ; next byte of table.
; bne :+
; inc z80_h
;:
;
; ldy #0
; lda (z80_hl),y ; fetch value from table.
; sta z80_b
ldd 2,x ; fetch value from table
std z80_bc
;order changed because we use de below
ldd ,x ; fetch value from table
std z80_de
stx z80_hl ; still need to add 4 to hl, wait until done with de
; ldy #2
; lda (z80_ix),y ; x coordinate in hl.
; clc
; adc z80_e ; add sine lb
; sta (z80_ix),y ; store new coordinate lb.
; ldy #3
; lda (z80_ix),y
; adc z80_d ; add sine hb
; sta (z80_ix),y ; store new coordinate hb.
ldx z80_ix
; D still contains z80_de
add 2,x ; x coordinate,
std 2,x ; store new coordinate
; ldy #4
; lda (z80_ix),y ; y coordinate in hl.
; clc
; adc z80_c ; add cosine lb
; sta (z80_ix),y ; store new coordinate lb.
; ldy #5
; lda (z80_ix),y
; adc z80_b ; add cosine lb
; sta (z80_ix),y ; store new coordinate hb.
ldd 4,x ; y coordinate
add z80_bc ; add cosine
std 4,x ; store new coordinate
ldd z80_hl ; add 4 to hl
addd #4
std z80_hl
rts
6502 vs 6803 code size example
Okay, who enabled auto completion by default on Notepad++? This should be associate with the language rather than a global setting. Now I have to turn it off, and on when I switch between C, and assembly. 😈
Since nobody's getting circuit boards out of China before CoCoFest, I don't feel a lot of pressure to write some code for a couple hardware projects I promised to help with. So, I'm translating more code from 6502 to 6803 for the Teaser project.
Just to give you an idea of the difference in code size, I've commented out the 6502 instructions, and placed the equivalent 6803 ones after each section. Notice how 8 instructions become 2 after iniob0, and 4 of the 6502 instructions are some of the slowest on that CPU? It's like this everywhere.
The Z80 references are due to the original code the 6502 is ported from coming from the Z80, and they are duplicating the register use with memory variables. Since the 6803's index register X is 16 bit, and can index anywhere in a 256 byte range off of X, we don't need to even change X here. The 16 bit D register even lets us load, and save two bytes at once even though they are separate variables.
The 6803 is far superior for accessing data structures, and this project uses a lot of them.
The on significant difference vs the 6502, is the 8 bit loop counter is placed in memory, and decremented there. Too bad Motorola didn't offer a direct addressing version of DEC, and INC instructions. The dearth of registers on the 6803 makes the direct page an obvious place for loop counters.
Sorry, if Blogger does bad things to the code formatting. I need to look up the page I was using to format, and colorize the code with off of my old computer.
;-------------------------------------------------------------
; Initialise all objects.
;
; Reset current room,y,x to start room,y,x for all objects
;-------------------------------------------------------------
iniob:
; lda #<objdta ; objects table.
; sta z80_x
; lda #>objdta
; sta z80_i
;
; ldx numob ; number of objects in the game.
ldx #objdta ; object table
stx z80_ix
;*************** use memory to hold loop counter
ldaa numob ; number of objects in the game
staa loopcounter
iniob0:
; ldy #35
; lda (z80_ix),y ; start screen.
; ldy #32
; sta (z80_ix),y ; set start screen.
; ldy #36
; lda (z80_ix),y ; find start y.
; ldy #33
; sta (z80_ix),y ; set start y.
ldd 35,x ; start screen, find start y
std 32,x ; set start screen, start y
; ldy #37
; lda (z80_ix),y ; get initial x.
; ldy #34
; sta (z80_ix),y ; set x coord.
ldaa 37,x ; get initial x.
staa 34,x ; set x coord.
; clc ; point to next object.
; lda z80_x
; adc #38 ; distance between objects.
; sta z80_x
; bcc :+
; inc z80_i
;:
ldaa #38 ; distance between objects.
abx ; point to next objects.
; dex ; repeat.
; bne iniob0
dec loopcounter
bne iniob0
rts
Since nobody's getting circuit boards out of China before CoCoFest, I don't feel a lot of pressure to write some code for a couple hardware projects I promised to help with. So, I'm translating more code from 6502 to 6803 for the Teaser project.
Just to give you an idea of the difference in code size, I've commented out the 6502 instructions, and placed the equivalent 6803 ones after each section. Notice how 8 instructions become 2 after iniob0, and 4 of the 6502 instructions are some of the slowest on that CPU? It's like this everywhere.
The Z80 references are due to the original code the 6502 is ported from coming from the Z80, and they are duplicating the register use with memory variables. Since the 6803's index register X is 16 bit, and can index anywhere in a 256 byte range off of X, we don't need to even change X here. The 16 bit D register even lets us load, and save two bytes at once even though they are separate variables.
The 6803 is far superior for accessing data structures, and this project uses a lot of them.
The on significant difference vs the 6502, is the 8 bit loop counter is placed in memory, and decremented there. Too bad Motorola didn't offer a direct addressing version of DEC, and INC instructions. The dearth of registers on the 6803 makes the direct page an obvious place for loop counters.
Sorry, if Blogger does bad things to the code formatting. I need to look up the page I was using to format, and colorize the code with off of my old computer.
;-------------------------------------------------------------
; Initialise all objects.
;
; Reset current room,y,x to start room,y,x for all objects
;-------------------------------------------------------------
iniob:
; lda #<objdta ; objects table.
; sta z80_x
; lda #>objdta
; sta z80_i
;
; ldx numob ; number of objects in the game.
ldx #objdta ; object table
stx z80_ix
;*************** use memory to hold loop counter
ldaa numob ; number of objects in the game
staa loopcounter
iniob0:
; ldy #35
; lda (z80_ix),y ; start screen.
; ldy #32
; sta (z80_ix),y ; set start screen.
; ldy #36
; lda (z80_ix),y ; find start y.
; ldy #33
; sta (z80_ix),y ; set start y.
ldd 35,x ; start screen, find start y
std 32,x ; set start screen, start y
; ldy #37
; lda (z80_ix),y ; get initial x.
; ldy #34
; sta (z80_ix),y ; set x coord.
ldaa 37,x ; get initial x.
staa 34,x ; set x coord.
; clc ; point to next object.
; lda z80_x
; adc #38 ; distance between objects.
; sta z80_x
; bcc :+
; inc z80_i
;:
ldaa #38 ; distance between objects.
abx ; point to next objects.
; dex ; repeat.
; bne iniob0
dec loopcounter
bne iniob0
rts
Tuesday, February 25, 2020
more on github
I just pushed the 6502 version of the code to print text on a graphics screen.
When I get time, the Atom, Atari, and Plus/4 code needs separated, and then I need to interface the code to the C compiler.
When I get time, the Atom, Atari, and Plus/4 code needs separated, and then I need to interface the code to the C compiler.
Monday, February 24, 2020
Teaser
This is something I started shortly before I got crazy busy last year.
What could I be translating from 6502 to 6803 assembly, and why does it keep saying z80?
😎
<sigh> Only 6000+ lines left to translate.
;--------------------------------------------------------------
; Display sprites.
;
; Input:
; IX = sprite table
;--------------------------------------------------------------
dspr:
; lda #(NUMSPR/2) ; number of sprites to display.
; sta sprcnt
ldx z80_ix
ldaa #(NUMSPR/2) ; number of sprites to display.
staa sprcnt
dspr0:
; ldy #0
; lda (z80_ix),y ; get sprite type.
; cmp #255 ; is it enabled?
; bne dspr1 ; yes, it needs deleting.
ldx z80_ix
ldaa 0,x ; get sprite type
cmpa #255 ; is it enabled?
bne dspr1 ; yes, it needs deleting.
dspr5:
; ldy #5
; lda (z80_ix),y ; new type.
; cmp #255 ; is it enabled?
; bne dspr3 ; yes, it needs drawing.
ldx z80_ix
ldaa 5,x ; new type.
cmpa #255 ; is it enabled?
bne dspr3 ; yes, it needs drawing.
dspr2:
; ldy #5
; lda (z80_ix),y ; copy new type.
; ldy #0
; sta (z80_ix),y
; ldy #6
; lda (z80_ix),y ; copy new image number.
; ldy #1
; sta (z80_ix),y
ldx z80_ix
ldd 5,x ;copy new type 5 and image number 6
std 0,x ;> to 0 & 1
; ldy #7
; lda (z80_ix),y ; copy new frame.
; ldy #2
; sta (z80_ix),y
ldaa 7,x ; copy new frame
staa 2,x
; ldy #8
; lda (z80_ix),y ; copy new y.
; ldy #3
; sta (z80_ix),y
; ldy #9
; lda (z80_ix),y ; copy new x.
; ldy #4
; sta (z80_ix),y
ldd 8,x ; copy new y & x
std 3,x
; clc
; lda z80_x
; adc #(TABSIZ*2) ; distance to next odd/even entry.
; sta z80_x
; lda z80_i
; adc #0
; sta z80_i ; next sprite.
ldd z80_ix
addd #(TABSIZ*2) ; distance to next odd/even entry. next sprite.
std z80_ix
dec sprcnt
bne dspr0 ; repeat for remaining sprites.
rts
dspr1:
; ldy #5
; lda (z80_ix),y ; type of new sprite.
; cmp #255 ; is this enabled?
; bne dspr4 ; yes, display both.
ldx z80_ix
ldaa 5,x ; type of new sprite
cmpa #255 ; is this enabled?
bne dspr4 ; yes, display both.
dspr6:
jsr sspria ; show single sprite.
jmp dspr2
; Displaying two sprites. Don't bother redrawing if nothing has changed.
dspr4:
; ldy #4
; lda (z80_ix),y ; old x.
; ldy #9
; cmp (z80_ix),y ; compare with new value.
; bne dspr7 ; they differ, need to redraw.
; ldy #3
; lda (z80_ix),y ; old y.
; ldy #8
; cmp (z80_ix),y ; compare against new value.
; bne dspr7 ; they differ, need to redraw.
ldx z80_ix
ldd 3,x ; a = old y, b = old x
cmpa 9,x
bne dspr7 ; they differ, need to redraw.
cmpb 8,x ; compare against new value.
bne dspr7 ; then differ, need to redraw.
; ldy #2
; lda (z80_ix),y ; old frame.
; ldy #7
; cmp (z80_ix),y ; compare against new value.
; jmp dspr7 ; they differ, need to redraw.
ldaa 2,x ; old frame.
cmpa 7,x ; compare against new value.
; jmp dspr7 ; they differ, need to redraw
bne dspr7 ; they differ, need to redraw
; ldy #1
; lda (z80_ix),y ; old image.
; ldy #6
; cmp (z80_ix),y ; compare against new value.
; beq dspr2 ; everything is the same, don't redraw.
ldaa 1,x ; old image.
cmpa 6,x ; compare against new value.
beq dspr2 ; everything is the same, don't redraw.
dspr7:
jsr sspric ; delete old sprite, draw new one simultaneously.
; jmp dspr2
bra dspr2
dspr3:
jsr ssprib ; show single sprite.
; jmp dspr2
bra dspr2
sprcnt: .byte 0
What could I be translating from 6502 to 6803 assembly, and why does it keep saying z80?
😎
<sigh> Only 6000+ lines left to translate.
;--------------------------------------------------------------
; Display sprites.
;
; Input:
; IX = sprite table
;--------------------------------------------------------------
dspr:
; lda #(NUMSPR/2) ; number of sprites to display.
; sta sprcnt
ldx z80_ix
ldaa #(NUMSPR/2) ; number of sprites to display.
staa sprcnt
dspr0:
; ldy #0
; lda (z80_ix),y ; get sprite type.
; cmp #255 ; is it enabled?
; bne dspr1 ; yes, it needs deleting.
ldx z80_ix
ldaa 0,x ; get sprite type
cmpa #255 ; is it enabled?
bne dspr1 ; yes, it needs deleting.
dspr5:
; ldy #5
; lda (z80_ix),y ; new type.
; cmp #255 ; is it enabled?
; bne dspr3 ; yes, it needs drawing.
ldx z80_ix
ldaa 5,x ; new type.
cmpa #255 ; is it enabled?
bne dspr3 ; yes, it needs drawing.
dspr2:
; ldy #5
; lda (z80_ix),y ; copy new type.
; ldy #0
; sta (z80_ix),y
; ldy #6
; lda (z80_ix),y ; copy new image number.
; ldy #1
; sta (z80_ix),y
ldx z80_ix
ldd 5,x ;copy new type 5 and image number 6
std 0,x ;> to 0 & 1
; ldy #7
; lda (z80_ix),y ; copy new frame.
; ldy #2
; sta (z80_ix),y
ldaa 7,x ; copy new frame
staa 2,x
; ldy #8
; lda (z80_ix),y ; copy new y.
; ldy #3
; sta (z80_ix),y
; ldy #9
; lda (z80_ix),y ; copy new x.
; ldy #4
; sta (z80_ix),y
ldd 8,x ; copy new y & x
std 3,x
; clc
; lda z80_x
; adc #(TABSIZ*2) ; distance to next odd/even entry.
; sta z80_x
; lda z80_i
; adc #0
; sta z80_i ; next sprite.
ldd z80_ix
addd #(TABSIZ*2) ; distance to next odd/even entry. next sprite.
std z80_ix
dec sprcnt
bne dspr0 ; repeat for remaining sprites.
rts
dspr1:
; ldy #5
; lda (z80_ix),y ; type of new sprite.
; cmp #255 ; is this enabled?
; bne dspr4 ; yes, display both.
ldx z80_ix
ldaa 5,x ; type of new sprite
cmpa #255 ; is this enabled?
bne dspr4 ; yes, display both.
dspr6:
jsr sspria ; show single sprite.
jmp dspr2
; Displaying two sprites. Don't bother redrawing if nothing has changed.
dspr4:
; ldy #4
; lda (z80_ix),y ; old x.
; ldy #9
; cmp (z80_ix),y ; compare with new value.
; bne dspr7 ; they differ, need to redraw.
; ldy #3
; lda (z80_ix),y ; old y.
; ldy #8
; cmp (z80_ix),y ; compare against new value.
; bne dspr7 ; they differ, need to redraw.
ldx z80_ix
ldd 3,x ; a = old y, b = old x
cmpa 9,x
bne dspr7 ; they differ, need to redraw.
cmpb 8,x ; compare against new value.
bne dspr7 ; then differ, need to redraw.
; ldy #2
; lda (z80_ix),y ; old frame.
; ldy #7
; cmp (z80_ix),y ; compare against new value.
; jmp dspr7 ; they differ, need to redraw.
ldaa 2,x ; old frame.
cmpa 7,x ; compare against new value.
; jmp dspr7 ; they differ, need to redraw
bne dspr7 ; they differ, need to redraw
; ldy #1
; lda (z80_ix),y ; old image.
; ldy #6
; cmp (z80_ix),y ; compare against new value.
; beq dspr2 ; everything is the same, don't redraw.
ldaa 1,x ; old image.
cmpa 6,x ; compare against new value.
beq dspr2 ; everything is the same, don't redraw.
dspr7:
jsr sspric ; delete old sprite, draw new one simultaneously.
; jmp dspr2
bra dspr2
dspr3:
jsr ssprib ; show single sprite.
; jmp dspr2
bra dspr2
sprcnt: .byte 0
The magic MC-10 keyboard trick
On the last episode of the CoCoTalk podcast (talk show?) the news section brought up the following video, where a BASIC program reads garbage from the keyboard when you wave your hand over it.
https://youtu.be/o6zssRDSjuE
I gave a brief explanation of why this happens on the show, but here is a little more detail about what is going on.
The Motorola 6803 is a microcontroller. It differs a bit from most 8 bit microprocessors because it has some built in hardware. Parallel I/O ports, serial port, timer, etc... To keep things somewhat simple, the MC-10 keyboard is wired to one of the built in parallel I/O ports. The program shown above sets that port to input mode, and then it just polls the input port, and prints whatever comes in on the screen.
The way the keyboard is wired to the 6803, it forms it's own buss of sorts on the system. The wires and circuit board traces form little antennas which pick up noise. It's been a while, but if I remember right, the human body can induce a current of up to 1.8 volts. I don't have a scope to hook up to it for verification, but that's probably what we'd see. While the port on the 6803 was designed to work with 5 volt parts, it seems just sensitive enough to pick up that voltage as high signals. Since the voltage isn't continuous on all the lines, the numbers change somewhat randomly.
If the keyboard had used a 2 layer board with a ground plane on the top side, and just passed the key connections through from/to the other side, this probably wouldn't happen. Also, if the keyboard buss had resistors tying the keyboard lines to ground on the read side of the circuit, that weak noise would have been dropped to a level that the 6803 wouldn't read. I don't think this was a matter of money, the engineer probably just didn't see it as a buss, so he didn't expect it, and this didn't show up in testing.
So why doesn't it cause a problem for BASIC? The BASIC interpreter outputs data to the keyboard to choose which row of keys to check, it performs debounce which dumps inconsistent data, etc...
I don't think the debounce is helping. More likely, the 6803's I/O port design can't read that low of a voltage under those circumstances, and that only happens when it's set just as input and you poll it, but that's a bit of a guess.
https://youtu.be/o6zssRDSjuE
I gave a brief explanation of why this happens on the show, but here is a little more detail about what is going on.
The Motorola 6803 is a microcontroller. It differs a bit from most 8 bit microprocessors because it has some built in hardware. Parallel I/O ports, serial port, timer, etc... To keep things somewhat simple, the MC-10 keyboard is wired to one of the built in parallel I/O ports. The program shown above sets that port to input mode, and then it just polls the input port, and prints whatever comes in on the screen.
The way the keyboard is wired to the 6803, it forms it's own buss of sorts on the system. The wires and circuit board traces form little antennas which pick up noise. It's been a while, but if I remember right, the human body can induce a current of up to 1.8 volts. I don't have a scope to hook up to it for verification, but that's probably what we'd see. While the port on the 6803 was designed to work with 5 volt parts, it seems just sensitive enough to pick up that voltage as high signals. Since the voltage isn't continuous on all the lines, the numbers change somewhat randomly.
If the keyboard had used a 2 layer board with a ground plane on the top side, and just passed the key connections through from/to the other side, this probably wouldn't happen. Also, if the keyboard buss had resistors tying the keyboard lines to ground on the read side of the circuit, that weak noise would have been dropped to a level that the 6803 wouldn't read. I don't think this was a matter of money, the engineer probably just didn't see it as a buss, so he didn't expect it, and this didn't show up in testing.
So why doesn't it cause a problem for BASIC? The BASIC interpreter outputs data to the keyboard to choose which row of keys to check, it performs debounce which dumps inconsistent data, etc...
I don't think the debounce is helping. More likely, the 6803's I/O port design can't read that low of a voltage under those circumstances, and that only happens when it's set just as input and you poll it, but that's a bit of a guess.
Thursday, February 20, 2020
More stuff on github
I'm dumping a lot of stuff to github.
Github
Github
Tuesday, February 18, 2020
The code for the expansion board I was working on for the VZ200 is up on github.
VZ Super-Expander
The IDE interface was going to be based on the TRS-80 Lo Tech interface.
The CPLD was just going to be used for address decoding to keep the pin count down. That would require some external chips for buffering, LED, etc..., but it was only two or three parts I remember right. The driver was going to be based on modified code from the Lo Tech driver just to keep things simple.
VZ Super-Expander
The IDE interface was going to be based on the TRS-80 Lo Tech interface.
The CPLD was just going to be used for address decoding to keep the pin count down. That would require some external chips for buffering, LED, etc..., but it was only two or three parts I remember right. The driver was going to be based on modified code from the Lo Tech driver just to keep things simple.
My project to do list:
A chess game for the MC-10. People asked me to do this, so some point in the next few months I'll see what I can do about it. They suggested I port MicroChess from the 6502, but if I can get the 6803 C compiler to actually build working code, you'll get a lot better chess game than that. The compiler seems to have some stack issues at the moment, so no promises.
More MC-10 ROM changes in the works, including a faster LOG function. The new LOG will eliminate some of the slow division in the current code, replacing it with multiplication that will use the hardware multiply instead. Functions that depend on LOG should be significantly faster, including SQR, SIN, and COS. Combined with the previous SIN, COS speedup, the 0.89 MHz MC-10 might beat the 1.77 MHz CoCo 3 generating that "Fedora" 3D plot, and Ahl's Benchmark will drop below the 1 minute mark, possibly around 45 seconds. That's half the factory ROM's original time. Another change is to drop the ELSE statement. Yeah, that's the first thing I added, but after the last round of changes, it's just slowing things down. The interpreter has to search for the end of the line looking for an ELSE statement when an IF fails. Without it, the interpreter just loads the address of the next line, and starts interpreting code. Hopefully, that will speed up non-math oriented code enough to top the 10% mark.
Port BASIC to a 68HC11 development board. I've made a lot of the changes already, but it will only use terminal I/O, so lots of stuff has to go. At the moment, the board is just sitting on my desk staring at me.
A few years ago I ported the UCSD Pascal P-Code (bytecode) interpreter to the 6803. The 16 bit support, 16 bit index register, and a few other features makes the code smaller, and faster than the 6502 version (the Apple Language System). I *think* all that's left to implement is the hardware interface code for the UCSD P-Machine. But it's never that easy is it? The MC-10 hardware is right in the middle of the memory map, and there is no disk drive. The MC-10's design does allow external hardware to disable the internal memory map (video, sound, ROM, and internal RAM), so, it just needs an external expansion that can disable this stuff. The MCX-128 will do some of this, but it doesn't work with the hi-res mode, so using my 64 column graphics text code is out. That leaves the 32 column, uppercase only, inverse "lowercase", VDG output for text. That would be horrid for Pascal. Maybe some hardware is needed here. Hmmmm...
The P-Code interpreter for Tiny Pascal (BYTE Magazine, 1978) may get a port. It's similar to UCSD Pascal, but it's simpler. A program could be compiled on the PC, and the bytecode could be tacked on to the end of the interpreter, allowing the whole thing to load from cassette. It might be fun to play with, but it's not a priority.
While I'm talking about bytecode interpreters... the author of FastBASIC for the Atari asked if I'd port the it's bytecode interpreter to the 6803. It would need over 2000 lines of assembly. I have avoided starting on it until I finish some other projects, but a few people may prefer BASIC over Pascal.
Finish the disassembly of the VZ-200 ROM. I was using msys (a Unix like development system that works under Windows), but someone broke the sed command in an update. The disassembly uses an automated script to generate code, labels, and to attach comments to the disassembly using sed. My new desktop machine has a Linux boot drive I can use when things like this happen, and hopefully sed isn't broken there as well.
I'm going to start uploading code to github including:
The Oric music player, the Apple II Mockingboard version, and the VZ200 version.
A port of the William Tell Overture 4 voice music program from the CoCo, to the VZ. This is unfinished since I no longer have hardware to test on, and having someone else in Australia test it just wasn't working. It had some sort of bug as of the last test, which I may have found, but it doesn't have all the music data. I don't have the magazine with the source code anymore, so I'd have to extract the data from the CoCo executable.
Some Veralog code for a VZ200 RAM, FLASH, IDE, sound board I was working on. It's just some address decoding, generating chip selects, and a small amount of address line generation for the paged memory. The pin count was a bit high for a small CPLD, so I was planning changes, but my VZ burned up with my house, so it hasn't been touched since. It's about 600 lines of verilog.
The 64 column, graphics text code for the 6502, Z80, and 6803.
That includes Atom, Atari, Plus/4, VZ200, and MC-10 versions.
The Plus/4 code still needs to set the graphics mode, and the memory map.
The Z80 VZ, and 6803 MC-10 versions have some untested optimizations.
As I work on this, I'll post video updates. Hopefully the quality will be better now.
Monday, February 17, 2020
No I'm not dead... not yet anyway
No I'm not dead, and my projects aren't dead. I just got busy working for several months, and I've had some computer issues. One laptop is totally dead and the other is kinda in two pieces. My new PC (AMD Ryzen 2700X), is gradually getting all the tools installed including multiple compilers, assemblers, custom syntax highlighting definitions, disassemblers, Quartus, PCB design tools...
Some projects are going to be placed on github, including some projects I've never mentioned.
Some projects are going to be placed on github, including some projects I've never mentioned.
Subscribe to:
Posts (Atom)