Page 1 of 2

Checking Free RAM in ML

Posted: Sat Oct 19, 2013 4:55 pm
by GreyGhost
Was wondering if their is a way to check free RAM in machine language. Was wanting to try writing a program similar to Mike's clock program that would show a running total of memory in the bottom 6 screen locations under the border as you were entering it into memory. Maybe even the line you are typing as you type it. That might be a feat in itself though. Might even be useful when a basic program is running to see memory being used.

Any ideas?

Posted: Sat Oct 19, 2013 10:40 pm
by Kweepa
Here's what BASIC does when you call FRE(0) (taken from http://www.mdawson.net/vic20chrome/vic2 ... sembly.txt):

Code: Select all

JSR $D526 ; go do garbage collection
SEC       ; set carry for subtract
LDA $33   ; get bottom of string space low byte
SBC $31   ; subtract end of arrays low byte
TAY       ; copy result to Y
LDA $34   ; get bottom of string space high byte
SBC $32   ; subtract end of arrays high byte
You should probably skip the garbage collection call if you're doing this in an interrupt, since it won't play nicely with BASIC.

You could print AY in hex to that part of the screen pretty easily. Alternatively you could use a routine from here:
http://www.codebase64.org/doku.php?id=b ... conversion
to convert to decimal first for printing.

Very nice idea, by the way!

As for the size of the line as you are entering it, as you say that would be a feat - as far as I know, the VIC doesn't attempt to "enter" the line until you press the RETURN key. You'd probably have to parse the line yourself, using the screen line link table at $D9 to find the start of the line.

Posted: Sun Oct 20, 2013 3:49 pm
by Jeff-20
I'm also interested in your idea. Let us know when you have something ready. I'd be excited to test it.

Posted: Mon Oct 21, 2013 3:43 am
by Boray
Where are you planning to put your code? The tape buffer could be a good choice.

Posted: Mon Oct 21, 2013 5:54 am
by GreyGhost
Yeah, that was my first choice. If I can make it small enough, maybe the rs-232 buffer. I've been thinking of other things that might be interesting to implement as well. Having a running total of free memory will be nice, but I'm thinking about being able to toggle variable, array and string space used. Might be helpful while a program is running to see these on the fly. Maybe a CTRL-F7 to switch between them. Depends on what I can squeeze into one of the buffers. LOL or maybe both of them. I definitely don't want to use any basic ram. So, I'm thinking the bottom of the screen will look something like this:

F28159:for free ram
V00032:for variables
A:arrays, S:string ect...

Who knows, may even sound a buzzer and flash the screen red when free ram is getting short. Getting kinda bloated now.

I haven't touched any code in over a year now, so it is gonna be a relearning experience for me.

I noticed that their is a Start of Variables, an End of variables and only an End of Strings, and an End of Arrays. Is the Start of Variables and End of Variables all inclusive? Meaning does it include strings, arrays, integer ect...? Are all they variables grouped together? How are the stacked in memory? Which is first, second ect..?

Posted: Mon Oct 21, 2013 9:01 am
by Kweepa
From the kernal disassembly again, here is the memory map:

Code: Select all

BASIC program
VARIABLES
ARRAYS

free space

STRINGS (growing down)
top of RAM
Note that every time you create a new variable, it has to move the arrays up in memory to accommodate it! You can see this in action at $D11D.

You could let the program cycle automatically through its outputs.

WimBasic implementation

Posted: Tue Oct 22, 2013 12:44 am
by wimoos
You mention the RS232 buffer. In VIC20, when you open an RS232 device, a receive buffer and a transmit buffer of each 256 bytes is grabbed from the top of Basic RAM.

The following code is the implementation of the MEM command in WimBasic. The MEM command sits behind the f8 key per default.
It uses $DDCD to display A:X in decimal on the screen. You cannot use that while in an interrupt routine because it might conflict with STR$ or LIST.

Regards,

Wim.

Code: Select all

;
LA021	.BYTE $0D 	 
	.TEXT "MEMORY" 	 
	.BYTE $BA 	 
	.TEXT "PROGRAM" 	 
	.BYTE $BA 	 
	.TEXT "VARIABLES" 	 
	.BYTE $BA 	 
	.TEXT "ARRAYS" 	 
	.BYTE $BA 	 
	.TEXT "STRINGS" 	 
	.BYTE $BA 	 
	.TEXT "FREE" 	 
	.BYTE $BA
LA029	.TEXT "BYTES" 	 
	.BYTE $8D
; 	 
LTAB2	.BYTE $37
	.BYTE $2D
	.BYTE $2F
	.BYTE $31
	.BYTE $37
	.BYTE $33
;
LTAB3	.BYTE $2B
	.BYTE $2B
	.BYTE $2D
	.BYTE $2F
	.BYTE $33
	.BYTE $31
;
;
	LDX  #$FA
	LDY  #$00
	STY  $84
	STY  $86
	.BYTE $2C
LLOOP	LDY  $87
	LDA  LTAB2-$FA,X
	STA  $83
	LDA  LTAB3-$FA,X
	STA  $85
	TXA
	PHA
	JSR  LA87B
	STY  $87
	LDY  #$00
	LDA  ($83),Y
	SBC  ($85),Y
	TAX
	INY
	LDA  ($83),Y
	SBC  ($85),Y
	LDY  #$0A      	 
	STY  $D3       	 
	JSR  $DDCD     	 
	LDY  #$10      	 
	STY  $D3       	 
	LDY  #LA029-LA021      	
	JSR  LA87B
	PLA
	TAX
	INX
	BNE  LLOOP
	RTS
	 
LA87B	LDA  LA021,Y   	 
	PHP            	 
	AND  #$7F      	 
	JSR  $CB47     	 
	INY            	 
	PLP            	 
	BPL  LA87B     	 
	RTS            	 

Posted: Tue Oct 22, 2013 8:09 am
by GreyGhost
My mistake. Not a buffer, but the memory area 664-767.

I'm glad you said something about $ddcd not working in an interrupt. I've been looking at about 50 bytes of code for the past 2 days wondering why it has been crashing on me. I'm using it right now just to get the rest of the program working. When finished, I'll have to STA each individual decimal number in it's place.

Thank you for the listing, this should be enough to get this thing working.

By the way, I have never ran into this before can you explain?

Code: Select all

LDY  #LA029-LA021     

Posted: Tue Oct 22, 2013 10:04 am
by tlr
GreyGhost wrote:By the way, I have never ran into this before can you explain?

Code: Select all

LDY  #LA029-LA021     
That equates to the number of bytes between those labes.

Things like this are common practice:

Code: Select all

msg:
    dc.b "string"
MSG_LEN    equ *-msg

Posted: Tue Oct 22, 2013 10:19 am
by wimoos
Hello Rob,

Just like tlr said. The assembler will compute the number of bytes between the two labels and will build an appriopriate LDY # instruction.
At runtime Y will be loaded with the value and the routine at LA87B will then print the text "BYTES", followed by <CR>.

Regards,

Wim.

Posted: Tue Oct 22, 2013 2:19 pm
by Mike
GreyGhost wrote:My mistake. Not a buffer, but the memory area 664-767.
The addresses from 659 to 672 inclusive are used by the KERNAL for the Pseudo 6551 registers. There's a 'free' area from 673 upwards, up to address 767 (the so-called program indirects). Actually, the Super Expander uses that area for workspace.
I'm glad you said something about $ddcd not working in an interrupt. I've been looking at about 50 bytes of code for the past 2 days wondering why it has been crashing on me.
That pretty much applies to *any* routine within BASIC interpreter and KERNAL. Most of these are not intended to be called from an interrupt. If you do so, it can happen that you re-enter a routine which has just half-executed as the interrupt occured. The second call from within the interrupt will then likely disturb internal state variables of that routine, and this leads to undefined behaviour once the interrupt exits to the foreground again.

Re: Checking Free RAM in ML

Posted: Mon Nov 25, 2013 4:28 pm
by Mike
I thought it might be a good idea a post a working solution before this thread dies of old age ...

Code: Select all

10 FORT=828TO951:READA:POKET,A:NEXT:SYS828
11 DATA 120,169,83,141,20,3,169,3,141,21,3,173,3,144,41,128,9,48,141,3,144,88,96,216,56
12 DATA 165,51,229,49,133,251,165,52,229,50,133,252,248,169,0,133,3,133,4,133,5,162,16
13 DATA 6,251,38,252,165,3,101,3,133,3,165,4,101,4,133,4,165,5,101,5,133,5,202,208,231
14 DATA 216,169,250,133,251,133,253,174,136,2,232,134,252,138,41,3,9,148,133,254,160,0
15 DATA 169,3,162,4,6,3,38,4,38,5,42,202,208,246,145,251,173,134,2,145,253,200,192,6
16 DATA 208,230,76,191,234
The code doesn't quite fit into the area 673..767, for this reason I had to put it into the tape buffer.

What is output as 'free space' is the difference between 'top of arrays + 1' (stored at $31/$32) and 'bottom of string space' (stored at $33/$34), neatly converted from binary to BCD to PETSCII. I reused a routine in MINIPAINT which is used there to output the block counts in the directory display, except it now doesn't bother to crop the leading zeroes.

In both versions I took the bin to BCD conversion from an example by Andrew Jacobs posted at http://www.6502.org. Otherwise, I'm not going to provide source code this time - you'll have to infer yourself how it works ...

... and if anyone wants to put an equivalent routine into 673 .. 767 - go ahead. :)

Re: Checking Free RAM in ML

Posted: Tue Nov 26, 2013 3:54 am
by wimoos
The code below takes 92 bytes and fits in the 673-767 area. Start with SYS673.

Regards,

Wim.

Code: Select all

	.org 673
	sei
	lda #ticket & $ff
	sta $0314
	lda #ticket >> 8
	sta $0315
	lda $9003
	and #$80
	ora #$30
	sta $9003
	cli
	rts

ticket	sec
	lda $33
	sbc $31
	sta $fb
	lda $34
	sbc $32
	sta $fc
	lda #$fa
	sta $03
	sta $05
	lda $0288
	adc #$00
	sta $04
	and #$03
	ora #$94
	sta $06
	ldy #$05
div3	ldx #$10
	lda #$00
div2	asl $fb
	rol $fc
	rol a
	cmp #$0a
	bcc div1
	sbc #$0a
	inc $fb
div1	dex
	bne div2
	ora #'0'
	sta ($03),y
	lda $0286
	sta ($05),y
	dey
	bpl div3
	jmp $eabf
	.end

Re: Checking Free RAM in ML

Posted: Tue Nov 26, 2013 1:01 pm
by Mike
wimoos wrote:The code below takes 92 bytes and fits in the 673-767 area. Start with SYS673.
Now, that's quite a feat. And you even kept the niceties I put in to adapt to the different RAM configurations, especially regarding the screen and colour RAM base addresses. 8)

I'd still keep the CLD in front of the interrupt server, though, in case the foreground program executes some instructions in decimal mode.

Cheers,

Michael

P.S. in case anyone is wondering about the use of the zeropage addresses 3..6 here, they're supposed to contain vectors to two routines for conversion between ASCII/PETSCII <-> FAC (floating point accumulator). As it happens, even though BASIC initialises these 4 bytes, neither BASIC itself, nor any program I know uses these vectors to jump to the corresponding routines, they're always directly called. Consequently, I regard these four bytes as essentially free (similar to $FB .. $FE) for own projects.

Re: Checking Free RAM in ML

Posted: Tue Nov 26, 2013 3:26 pm
by wimoos
I'd still keep the CLD in front of the interrupt server, though, in case the foreground program executes some instructions in decimal mode.
Just like the Zp $03-$06 and $FB-FE are never used in CBM Basic or the Kernal, there is no instance of a SED. So a CLD would not be needed.... :D

Regards,

Wim.