Jump to content
IGNORED

Action! Source Code


Recommended Posts

Just located one of my most-hated bugs:

 

;

; .BYTE 0,0,0,0,0,0,0,0 ; 7

strig tax

lda $d010,x

sta args

rts

;

 

Strig() reads the hardware register instead of the shadow register. This made my game totally uncontrollable because Action! is so fast, the bouncing of the mechanical trigger is visible.

Edited by JAC!
  • Like 2
Link to comment
Share on other sites

Looks like some things were foreseen in the lexer/parser but didn't make it into the language definition. They exist as unused token definitions in the lexer.

 

- case/esac

- code/edoc

- real

- string

- for ... downto

Link to comment
Share on other sites

And finally I manged to get the logic behind the bank id straight. The issue was the release source uses ebank=1 for the editor bank. But actually the value use in the ROM is 3 except on the bank id location itself ($AFFF). The trick behind all that is that OSS type 15 carts only use bits 3 and 0 for bank selection. Hence ebank=3 gives the correct result and the bank id (in fact all of them) must be masked with %1001.

 

bankmsk	equ	%1001			;Only bit 3 and 0 are relevant

	.if cartridge_type = 15		;OSS one chip 16 KB cartridge 
ebank	equ	3			;Editor bank, was 1 in original source
lbank	equ	0			;Library bank
cbank	equ	9			;Compiler bank
	.else
	.error "Unsupported cartridge type ", cartridge_type, ". Use 15 or 43."
	.endif

	.align	el+$0fff,$00	; Fill with empty bytes instead of $ff.
	org	el+$0fff
	.byte	ebank & bankmsk	; Bank identifier at end of bank.
Et voila:

Comparing files ACTION.rom and ACTION-TYPE-15.ROM

FC: no differences encountered

 

I also managed to add structuring for the majority of labels. That means there are not so many global labels anymore. Instead nested scopes provide context is restrict visibility. In higher level languages you'd call that "public" and "private". Editor, Monitor, Parse (Lexicon) and Compiler are now properly separated in terms of symbols.

 

post-17404-0-64505900-1423446203_thumb.png

 

Interesting for me: This was the first time I really needed the ".LOCAL" feature of MADS. It allows for having the same scope ("name") merged from different parts of the file. Because neither the editor nor the compiler fit into their available 4k bank, part of their code was moved by the original author to the main bank. By using ".local compiler" in both banks, I can address them logically as one again.

 

	icl	"SCREEN.MAC.asm"
	.local	compiler	; Main bank part of the compiler
	icl	"compiler/LEXICON.asm"
	.endl
	icl	"MAIN.MSC.asm"
	icl	"MAIN.BNK.asm"
mainend
	.align	ml+$08d8,$00	; Fill with empty bytes instead of $ff
	org	ml+$08d8
	.local	editor		;Main bank part of the editor
	icl	"editor/EDIT.FND.asm"
	icl	"editor/EDIT.SUB.asm"
	icl	"editor/EDIT.TAB.asm"
	.endl
editend
	.align	ml+$0a80,$00	; Fill with empty bytes instead of $ff.
	org	ml+$0a80
	icl	"AMPL.SEG.asm"
Edited by JAC!
  • Like 6
Link to comment
Share on other sites

I think floating point is left difficult to encourage you not to use it. j/k

 

It could be a little easier to use. Using the FP routines from assembler or Action isn't bad to the point of being unusable. I did a couple of programs that used the routines when translating a BASIC program to Action. I think at least one was from one of the Compute Books ~Book Two of Atari Programming, Point Set Graphics.

 

Much of the need for FP would be eliminated easier by having something like a long integer and would probably be easier to implement.

Link to comment
Share on other sites

:-)

 

As a scientist I am 100 % with you. This goes even back to a dream a have: Fortran 77/90 for Atari...

 

Well, let's give the people some time for developing.

 

My blueprint is as follows:

 

(Atari Basic Ver. C (source code we already have), TurboBasic XL (source code is in the making), Basic XL (source code we already have), Basic XE (), Altirra Basic (source code we already have), MS Basic I and II(?) to finally build the last Atari Super Basic on an open source base.

 

Then(!) there has to be the FP integrated: here is my plan: OS source listing we already have, plus the Atari Calculator routines:

 

https://atariwiki.org/wiki/Wiki.jsp?page=Atari%20Calculator

 

please go up to the end of the page, plus the fast ones from Charles Marslett. Goal: Poke "precision,2" for 2 digits, up to 15 or 16...

 

Action! is already in the making.

 

Mac/65 or a Super Assembler. Well, that would be hard, MADS we do have, but we will see.

 

We live in interesting times... :-)

Link to comment
Share on other sites

Just located one of my most-hated bugs:

 

;

; .BYTE 0,0,0,0,0,0,0,0 ; 7

strig tax

lda $d010,x

sta args

rts

;

 

Strig() reads the hardware register instead of the shadow register. This made my game totally uncontrollable because Action! is so fast, the bouncing of the mechanical trigger is visible.injj

 

BTW: Great work!

 

Thanks for pointing this out because it makes it possible to do a work around if it becomes a problem. It probably should be left as is in the official cartridge just in case someone needs it that fast or has already adapted their program to account for it. It's pretty easy to just read the debounced shadow register under program control.

Link to comment
Share on other sites

I see it the other way around. All other functions use the shadow registers, only this only bails out with no reason. There's a reason why the shadow registers are there for all input controls: Updates more frequent than the frame rate are useless and can even break your control flow if you're not careful. Well unless you turn use the joystick trigger as digital analyzer, but esp. then you'd never go via a function call with it's overhead to read the hardware. You'd simply define INPUT = $D010, OUTPUT=$D01A and code something like DO:OUTPUT=INPUT<<2:OD .

 

In fact directly using the hardware registers is one of the most frequent bug in software released for the 8-bit in recent years. You don't have any issue in emulation and the on real hardware the game becomes uncontrollable and annoying and you don't know why.

Edited by JAC!
Link to comment
Share on other sites

I see it the other way around. All other functions use the shadow registers, only this only bails out with no reason.

To me, it looks like a conscious choice, and you forgot, in your game, to enable latching of TRIG inputs with GRACTL bit 2.

Edited by Kr0tki
Link to comment
Share on other sites

99% of problems are just solved by documenting the behavior. As KrOtki points out, set GRACTL. As JAC points out, could be fixed in cart which in no way inhibits your ability to directly read the hardware register. I'm not sure about the runtime packages because at least one is a directly copy of the cart routines, all can be patched or edited to do what you actually want.

 

There's no way of knowing if there was a piece of hardware that actually needs the routine as written. It is probably inconsequential at this stage, something like Mr. Parker used an 800 with a Corvus HD that needed it???

 

For any substantial Action! program, they all end up being a compile from disk. Pretty easy to patch the runtime to make sure it is doing what you intended. i.e.

BYTE FUNC STrig=*(BYTE p)
[$29$03$AA$BD$84$02$85$A0$60]
Link to comment
Share on other sites

The name of the function is the name of the shadow register.

Atari Basic (which is the defining base for all these function and their names) uses shadow registers for everything.
The Action! joystick routines published in the OSS Action! toolkit use shadow registers.
The other available 3rd party runtimes all use shadow registers for everything.
Nobody presses a fire button more than 50 times a second.
I personally spent hours trying to find out why a simple 4 line program transferred from Atari Basic didn't work.
That are enough reasons for me personally to consider this a fix. :)

Edited by JAC!
  • Like 3
Link to comment
Share on other sites

Right with the one possible exception of the runtime that just copies the routines directly from the cart. I can't recall the name of the programmer but I think you can find it in the umich Atari 8 bit archive if you need to know his name for some reason. This would of course means it copied the bug.

 

AFAIK, not many programmers<0?> used that technique/RT as people mostly used the Jeff Reister PD RT or commercial RT package.

 

I may have to revisit some of my odd hacks. I recall/still have the prototype of a single joystick port EPROM programmer I made. I used three 74ls164 to convert bit wise data into a byte and address. Pretty sure I had huge problems with denouncing the circuit. I think I used the 4 bits of port to handle clock, control, and data, and maybe Strig to read it back. Odd because it was digital but the noise introduced by hard switching and RFI blocking components on the J/S was enough to glitch the circuit.

Link to comment
Share on other sites

Spent the whole day adding yet more structure. The source is now organized in 39 separate files in 6 separate folders (compiler, editor, ampl, lib, main, root). 796 of of the 981 labels now have qualifiers, i.e. the are no longer plain global labels like "putch1" but "screen.putch.putch1". This gives locality to the labels and help to relate the label with the module or source file it is coming from. The remaining global labels are mainly system equates, which is OK. The source still compiles 100% to the original cartridge, which is still important at the current state to ensure I didn't break something already.

 

post-17404-0-27100500-1424130417_thumb.png

 

I also added the output of the "free" space available on the cartridge:

 

Aligning $B8D4 - $B8D8($0005 bytes free)

Aligning $BA7D - $BA80($0004 bytes free)

Aligning $BFF1 - $BFFA($000A bytes free)

Ending switched bank LL/LBANK: $AFFE - $AFFF($0002 bytes free)

Ending switched bank CL/CBANK: $AFFD - $AFFF($0003 bytes free)

Ending switched bank EL/EBANK: $AFFD - $AFFF($0003 bytes free)

 

So a total of 27 bytes, but as you can see in each bank, well... It must have been a hell of a job scramming it all in there. No wonder some commands had to be left out. There's heavy reuse across all modules and banks. This reuse actually breaks the program structure, but it saved some precious bytes. That's also why the main bank contains arbitrary code fragments from all other banks. Obviously the code was shifted "here and there" manually to find a best fit.

 

But the total killer code is the hash table which is used to map key words and procedure names to their definition in the ROM. The low-bytes of the hash values are used as index in a lookup table. And where there were gaps in the hash values, some small code fragments were squeezed in.

 

.byte <??en56
.byte <en3
.byte 0,0 ; 2
;
; .BYTE 0,0,0,0,0,0,0,0,0,0
; .BYTE 0,0,0,0,0,0,0,0,0 ; 17
??en6 .byte 6,'PrintF',200
.word libio.prtf ; #117
.byte 6,17,12,12,12,12,12
;
.byte <??en61
.byte <??en35
.byte 0 ; 1
.byte <??en39
There's even a hidden 3rd copyright notice encoded:

;
; .BYTE 0,0,0,0,0,0,0,0,0,0 ; 10
; (c)1983ACS in internal char. qcode
;copyright
	.byte	8,99,9,17,25,24,19,33,35,51
If this table is every moved one byte in either direction, it will probably go to hell with no way of knowing whether another valid sequence exists at all. Edited by JAC!
  • Like 4
Link to comment
Share on other sites

Well, if there is ONE thing, a compiler is supposed to do, then it's compiling HELLO WORLD correctly :-).

New build with 16k ROM and a first XEX version. I think the screen is not cleared correctly when leaving the editor, but the HELLO world is compiled & printed now.

ACTION.zip

Edited by JAC!
  • Like 3
Link to comment
Share on other sites

Ultimately, that's the plan. But for now it's very important to be able to back-track all my syntactic changes to make sure it is 100% compatible to the original. The result are of course lot of conditional assembly blocks that make the source more complicated overall.

 

;	RstBank()
;	---------
rstbank	.proc
	.if	.def bank
	php	
	pha	
	tya	
	ldy	curbank
rbank1	sta	bank,y
	tay	
	pla	
	plp
	.endif
init	rts	
But they allow me to gradually remove the parts will not be required anymore in future. OSS bank switching and ROM protection belong to this.

 

;SPLInit .proc ; init compiler RAM	;TODO This should be a subroutine

	.if	.def ramzap
	.if	ramzap
	jsr	editmain.fmcmd.zap4
	.else	
	nop	
	nop	
	nop	
	.endif
	.endif
My plan is to have a slightly modified OSS compatible version that can replace the original. Given the 27 free bytes, that will include only simple things like case-insensitive search (which I once did as patch), less anyoing "BEEEEEEEEEEEEEEEEEEEEEEP" and the mentioned runtime lib fixes.

I'll freeze that version as 3.7 then in the original memory layout.

 

Everything beyond that will result XEX and ROM version depending on the demand. Maybe I'll start a poll then to ask. I think a XEX version with support to put itself under the OS or into extended RAM (so it doesn't get lost when the program crashes) will be the best options. Also I don't have to fiddle around with ROM size limits then.

 

For this version I will no longer stick to the original memory layout and will also untangle the source. In fact the XEX and CAR in my previous post already uses a better memory layout and have all banking and ROM protection stuff removed:; $D6 bytes free in the 16 ROM now.

  • Like 3
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...