Jump to content
IGNORED

Programmatically switching off BASIC


Recommended Posts

I understand that Bit 1 of the value stored as the PORTB address is used to disable the built-in BASIC routines in XL and XE machines. I would like to know how and perhaps more importantly when to do this from inside a machine code programme.

 

My guess is that you would do it during execution of the code pointed to by INITAD and physically perform the disabling by OR'ing hexadecimal 2 (so 00000010 in binary) against the current value of PORTB. In MADS the programme snippet might look like this:

                                                ;@com.wudsn.ide.asm.outputfileextension=.xex

                    ICL "Atari 8-Bit Memory Constants.asm"

                    INI INITIALIZE
                    RUN START_PROGRAMME


                    ORG $0600

INITIALIZE          clc
                    cld
                    lda PORTB
                    ora $2
                    sta PORTB
                    rts


                    .ALIGN $A000

START_PROGRAMME     ...
                    <programme goes here>
                    ...

However that is only a guess. I am on the right lines?

Link to comment
Share on other sites

You must place the INI after the INITIALIZE routine. That way the loader will first load the INITIALIZE routine and then it will load the INI segment and JSR to the previously loaded INITIALIZE routine. Then the loader will continue loading subsequent segments. The RUN segment can be anywhere however, since the loader only processes it once the file has been fully loaded. See also EXE File Format.

  • Like 2
Link to comment
Share on other sites

Yep. No need really for the clc and cld though. It's real annoying to have a program fail because you didn't disable Basic so always a pro touch to disable it this way. There's also the Ram based flag at $3F8 that's a good idea to set nonzero as well so it carries over the behaviour on warmstart.

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

You must place the INI after the INITIALIZE routine. That way the loader will first load the INITIALIZE routine and then it will load the INI segment and JSR to the previously loaded INITIALIZE routine. Then the loader will continue loading subsequent segments. The RUN segment can be anywhere however, since the loader only processes it once the file has been fully loaded. See also EXE File Format.

 

I think I am following you Xuel; so, if we use the same programme fragment as before then you are saying it should be layed out like this:

                                                ;@com.wudsn.ide.asm.outputfileextension=.xex

                    ICL "Atari 8-Bit Memory Constants.asm"


                    ORG $0600

INITIALIZE          clc
                    cld
                    lda PORTB
                    ora $2
                    sta PORTB
                    rts


                    INI INITIALIZE
                    RUN START_PROGRAMME


                    .ALIGN $A000

START_PROGRAMME     ...
                    <programme proper goes here>
                    ...
Edited by morelenmir
Link to comment
Share on other sites

Yep. No need really for the clc and cld though. It's real annoying to have a program fail because you didn't disable Basic so always a pro touch to disable it this way. There's also the Ram based flag at $3F8 that's a good idea to set nonzero as well so it carries over the behaviour on warmstart.

 

I will add that address as well then Rybags!

 

I was also interested by your suggestion about the CLC and CLD opcodes - obviously I am not in any way arguing with you, but the only reason I include them in my programme boilerplate is because 'Atari Roots' says it is an essential habit. Admittedly I have read Phaeron and FJC both saying that book is not perhaps the most reliable source of information!!!

Link to comment
Share on other sites

I think I am following you Xuel; so, if we use the same programme fragment as before then you are saying it should be layed out like this:

 

Yep. Also, since the initialize segment is only needed once you can put it at $2000 even if you're later going to load another segment there or use that area for other purposes. That way, loaders that use page 6 will still work with your program. A general rule of thumb is that $2000-$BFFF is the safe area for segments to load into with an added caveat that you might also want to disable the display (SDMCTL=0, DMACTL=0) in your INITIALIZE routine to avoid overwriting an active display list.

Link to comment
Share on other sites

 

Yep. Also, since the initialize segment is only needed once you can put it at $2000 even if you're later going to load another segment there or use that area for other purposes. That way, loaders that use page 6 will still work with your program. A general rule of thumb is that $2000-$BFFF is the safe area for segments to load into with an added caveat that you might also want to disable the display (SDMCTL=0, DMACTL=0) in your INITIALIZE routine to avoid overwriting an active display list.

 

Many thanks Xuel!!! That is invaluable information and it is basic things like this, more about the practical than theoretical steps of Atari ASM that I am really lacking and hope to learn. I think I have a solid grounding in most of the nuts and bolts of general programming and even some grasp of assembler itself, but how to apply that to the Atari eco-system is currently very daunting to me.

 

The situation you describe does actually touch on a wider area that has puzzled me in the past - that of 'segments' within a programme and how the loading process handles them. So, as a broad first question is it possible to define segments in your source code that are loaded sequentially and that even overlap or totally overwrite the memory addresses that previous segments were loaded on to?

Link to comment
Share on other sites

So, as a broad first question is it possible to define segments in your source code that are loaded sequentially and that even overlap or totally overwrite the memory addresses that previous segments were loaded on to?

 

Yes. The EXE format is quite simple. It's just a stream of segments. Each segment is just HEADER*, START, END, DATA, where HEADER is $FFFF for the first segment and optional for later segments, START and END are 16-bit starting and ending addresses and DATA is END-START+1 bytes of segment data. Even INI and RUN segments follow this format. They just load a 16-bit address to $2E2 or $2E0 respectively. Later segments can overwrite earlier segments.

Edited by Xuel
Link to comment
Share on other sites

 

Yes. The EXE format is quite simple. It's just a stream of segments. Each segment is just HEADER*, START, END, DATA, where HEADER is $FFFF for the first segment and optional for later segments, START and END are 16-bit starting and ending addresses and DATA is END-START+1 bytes of segment data. Even INI and RUN segments follow this format. They just load a 16-bit address to $2E2 or $2E0 respectively. Later segments can overwrite earlier segments.

 

So, this is the (mostly) working programme - a very, very simple display list and data:

		      ICL "Atari 8-Bit Memory Constants.asm"		;INCLUDE ATARI MEMORY LABEL DEFINITIONS


		        ORG $2000
				
INITIALIZE	        lda PORTB
		        ora #$02
		        sta PORTB
			 	
		        lda #$00
		        sta SDMCTL
		        sta DMACTL
											
		        rts		
				
		        INI INITIALIZE
		        RUN START_PROGRAMME				

		        ORG $2100
				
START_PROGRAMME	        lda #$00		;
		        sta SDMCTL		;Store literal 0 in SDMCTL - therefore switch off ANTIC.
				
			lda #CHARACTER_MAP/256
			sta CHBAS
				
			lda #DISPLAY_LIST&255	;
			sta SDLSTL		;Extract low BYTE from DISPLAY_LIST and store it in SDLSTL
			lda #DISPLAY_LIST/256	;
			sta SDLSTL+1		;Extract high BYTE from DISPLAY_LIST and store it in SDLSTL+1
						;
						;Therefore tell antic the starting address of the custom display list.
				
			lda #$22       		;
			sta SDMCTL     		;Store literal $22 in SDMCTL - therefore switch ANTIC back on.
				
END_PROGRAMME		jmp END_PROGRAMME

			.ALIGN $2400
CHARACTER_MAP		INS "character_map.FNT"


			.ALIGN $2800
				
DISPLAY_LIST		.BYTE $70,$70,$70	;Discard 24 scan lines
			.BYTE $48		;8 scan lines		= 10 BYTEs x 4 pixels per BYTE 	= 40 pixels per line
			.WORD DISPLAY_MEMORY
			.BYTE $08		;8 scan lines		= 10 BYTEs x 4 pixels per BYTE 	= 40 pixels per line
			.BYTE $08		;8 scan lines		= 10 BYTEs x 4 pixels per BYTE 	= 40 pixels per line
			.BYTE $08		;8 scan lines		= 10 BYTEs x 4 pixels per BYTE 	= 40 pixels per line
			.BYTE $02		;8 scan lines		= 40 BYTEs x 1 character per BYTE 	= 40 characters per line
			.BYTE $08		;8 scan lines		= 10 BYTEs x 4 pixels per BYTE 	= 40 pixels per line
			.BYTE $03		;10 scan lines		= 40 BYTEs x 1 character per BYTE 	= 40 characters per line
			.BYTE $08		;8 scan lines		= 10 BYTEs x 4 pixels per BYTE 	= 40 pixels per line
			.BYTE $06		;8 scan lines		= 20 BYTEs x 1 character per BYTE	= 20 characters per line
			.BYTE $08		;8 scan lines		= 10 BYTEs x 4 pixels per BYTE 	= 40 pixels per line
			.BYTE $07		;16 scan lines		= 20 BYTEs x 1 character per BYTE	= 20 characters per line
			.BYTE $08		;8 scan lines		= 10 BYTEs x 4 pixels per BYTE 	= 40 pixels per line
			.BYTE $04		;8 scan lines		= 40 BYTEs x 1 character per BYTE	= 40 characters per line
			.BYTE $08		;8 scan lines		= 10 BYTEs x 4 pixels per BYTE	= 40 pixels per line
			.BYTE $05		;16 scan lines		= 40 BYTEs x 1 character per BYTE	= 40 characters per line
			.BYTE $08		;8 scan lines		= 10 BYTEs x 4 pixels per BYTE	= 40 pixels per line
						;= 130 scan lines (62 scan lines lines remaining)
			.BYTE $41
			.WORD DISPLAY_LIST


		        .ALIGN $3000
				
DISPLAY_MEMORY	        .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
                        .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
		        .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
			.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
			.BYTE "Custom Display List.                    "
			.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
			.BYTE "Custom Display List.                    "
			.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
			.BYTE "Custom Display List."
			.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
			.BYTE "Custom Display List."
			.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00				
			.BYTE $3B,$3C,$3D,$3E,$3F,$40,$C1,$C2,$43,$44,$45,$46,$00,$00,$47,$48,$C9,$CA,$4B,$4C,$4D,$4E,$4F,$50,$D1,$D2,$53,$54,$00,$00,$55,$56,$D7,$D8,$D9,$DA,$5B,$5C,$5D,$5E
			.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
			.BYTE $3B,$3C,$3D,$3E,$3F,$40,$C1,$C2,$43,$44,$45,$46,$00,$00,$47,$48,$C9,$CA,$4B,$4C,$4D,$4E,$4F,$50,$D1,$D2,$53,$54,$00,$00,$55,$56,$D7,$D8,$D9,$DA,$5B,$5C,$5D,$5E
			.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00

The first time this is run it works properly and as expected. However if I press 'Reset', instead of restarting the programme the machine drops to a BASIC prompt, despite the INI segment pointing to the INITIALIZE code which should disable BASIC each time... I feel like I almost have this down, but its always that last little bit of understanding that's hardest to really focus down on!

Link to comment
Share on other sites

Hmmm,

 

if Reset should restart the program, this would mean your program is Reset-proof. So the only way to reboot the real Atari would be to power off and on again. There are, alas, dozens if not hundreds of A8 programs that behave the same. However, its not good powering off/on a machine all the time that is more than 30 years old. In my eyes it would be much better if Reset does a coldstart (similar to Poke 580,1), so you can reboot the sytem by just pressing the Reset key... (and no, I never pressed Reset by mistake).

  • Like 1
Link to comment
Share on other sites

You said you were going to add non-zeroing of $03F8, but I don't see that anywhere. It must be done

or you have the situation you find yourself in BASIC with RESET press. The system is using it as

a warmstart flag for turning on BASIC if it's zero. System sets it to zero when OPTION is not

pressed on powerup or RESET. You could store portb value there before the ORA #02 so you would

have that information stored before you turn off BASIC at portb and this would comply with

Mapping XL version advice on page 211 -- 3F8, "Must be in sync with disabling of ROM BASIC".

  • Like 1
Link to comment
Share on other sites

You said you were going to add non-zeroing of $03F8, but I don't see that anywhere. It must be done

or you have the situation you find yourself in BASIC with RESET press. The system is using it as

a warmstart flag for turning on BASIC if it's zero. System sets it to zero when OPTION is not

pressed on powerup or RESET. You could store portb value there before the ORA #02 so you would

have that information stored before you turn off BASIC at portb and this would comply with

Mapping XL version advice on page 211 -- 3F8, "Must be in sync with disabling of ROM BASIC".

 

Right you are 1050 - many thanks as ever!!! I had overlooked that tip as when I reffered to $3F8 in 'Mapping The Atari' it reported the location as part of the cassette IO buffer. However I was not taking in to account the changes between the 400-800 memory layout and the updates that were made for the XL's and XE's. Moreover I did not have those labels in my memory location label header file either. I will have to update that as well! Anyway, just as you suggest if I store the PORTB contents in there - therefore make BASICF non-zero - it works like a charm. Now when I press 'RESET' the programme falls to 'Self-Test', which is perfect.

 

Now I need to look at the technique for making the code 'Reset Proof' but that is another topic!

Edited by morelenmir
Link to comment
Share on other sites

Closely related to the idea of disabling BASIC is the issue of the 'OS floating-point pack'.

 

If 'Atari Roots' is to be trusted there are quite a few bytes of invaluable storage on page zero which seem to be monopolized by that part of the OS. Moreover I have read both FJC and Phaeron saying how the floating-point routines are almost never used. I wonder if it is possible therefore to also switch off these routines along with BASIC and reclaim the memory locations $D4 to $FF. That would be 43 extra bytes free to use on Page0 if my hex-arithmetic is still good, so very valuable space indeed.

Link to comment
Share on other sites

Just don't call the FP and you can use everything from $80-$FF.

 

Many thanks Jon - that's... 127 free bytes then!!! No shortage at all! Weird how all the books talk about Page0 being almost 'forbidden territory'.

 

I guess its just a case of continuing to ignore the floating-point routines then!

Link to comment
Share on other sites

128 bytes, but yes: FP is a zero page hog, and I avoid it like the plague when I'm writing a large application, and this presents few problems since the occasions when FP is actually required have been few and far between. And when I did need FP (in APT FDISK), I was working with 32-bit numbers anway, so it was more economical to code the fractional stuff myself.

  • Like 2
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...
 Share

  • Recently Browsing   0 members

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