Jump to content
IGNORED

Flexible Kernel Code


Just Jeff

Recommended Posts

Good Morning..

 

Is there a way to run op codes from RAM? I have a kernel band with some slack time, it would be nice to re-use it more by say- storing an op code and operand in RAM that will either change an HMMx, or COLUx, etc and somehow run it.

 

Right now, the best thing I can think of for making the band flexible, is a jmp.ind using a pointer in RAM but I'm trying to find out if there is anything quicker. (I I also think this might force me to create giant jump tables with mostly nothing in them if I don't have a lot of things to do.

 

Thanks!

Link to comment
Share on other sites

I've done some googling, and it is possible. I also know you can do self modifying code - changing the code in RAM and /then/ executing it.

 

I think the general idea is to point the program counter to the address locations in RAM.

 

So you'd need to set RORG to somewhere between the beginning of RAM ($80) and the end of RAM, I think.

Edited by vidak
  • Like 1
Link to comment
Share on other sites

Yes, the CPU doesn't care if it's reading code from ROM or RAM, it just keeps fetching and executing them from wherever the program counter indicates. Just copy the code to RAM (or generate it on the fly if that's what you're going for) and JMP/JSR to it.

  • Like 1
Link to comment
Share on other sites

Considering how little ram there is you may be better off using a indexed store to accomplish the same thing.

; Calculate which register to update wherever works best for you
lda #HMM0
sta $80


; Load X with the register in the kernel
ldx $80
lda #$e0
sta 0,x ; Which register is written to is now dynamic


If all you want to do is toggle between two registers you could use xor. I.E. COLUP0 ^ $01 = COLUP1 and COLUP1 ^ $01 = COLUP0

  • Like 1
Link to comment
Share on other sites

Considering how little ram there is you may be better off using a indexed store to accomplish the same thing.

; Calculate which register to update wherever works best for you
lda #HMM0
sta $80


; Load X with the register in the kernel
ldx $80
lda #$e0
sta 0,x ; Which register is written to is now dynamic


If all you want to do is toggle between two registers you could use xor. I.E. COLUP0 ^ $01 = COLUP1 and COLUP1 ^ $01 = COLUP0

 

I think this might satisfy most of what I was aiming for. I think I would have to add some more code that checks what scan line I'm on and if there are any updates for it. Thanks!

  • Like 1
Link to comment
Share on other sites

Could I have done something leaner?

 

Here's what I came up with so far and its a lot bigger that I thought it would be- I managed to blow up ZackAttack's code into 46 cycles to update only one register. I think it will fit because I can break it up a bit. Note: I start with 53 cycles of SLEEPs and 28 additional cycles wasted by a WSYNC and a BNE for the loop. (over the course of two lines.)

 

My goal was to have the band highly reusable while replacing some NOPS, and have the smallest tables I could. I think it will do that. Here's a table with a few example values:

SpecialInstructions:
	
	
;The first line to be changed needs to be seeded.
	

SIRegister:		; Specify which register will be updated
	.byte HMP1,	COLUP0,		GRP0,		ENABL
	
SIValue:		; The value to be placed in the register
	.byte 0,	YELLOW,		%10101010,	$02
	
SINext:			; The line number where the next register will be updated
			; (Compared to a Decrementing ScanLine)
	.byte 131
	.byte 110
	.byte 108

And here's the code:


	; Test to see if there are any register changes on this line
	
	lda ScanLine		; 3 3 See what scan line we're on
	cmp SILineNumRAM	; 3 6 See if it matches the stored next line to be changed
				; The first one of these will have to be seeded before the kernel

	bne NoChanges		; 2,3 8,9 If not skip over the change routine

	; if this line has a register change ; 8
	
	stx ScratchRAMX			; 3 11 Borrow the x register for register offset
	sty ScratchRAMY			; 3 14 Borrow the y register for data table offset
	ldy SIIndexRAM			; 3 16 y is the data table offset
	ldx SIRegister,y		; 4 20 x is an offset that matches registers (0,x)
	lda SIValue,y			; 4 24 load the value that will go in the register
	sta $0,x			; 4 28 store the value in the register
	
	; Now update where next change will happen
	
	lda SINext,y	     ; 4 32 Load the next line number that will receive an update
	sta SILineNumRAM     ; 3 35 Store it where it will be compared to Scanline later
	inc SIIndexRAM	     ; 5 40 This will be the next table offset (y).

	ldx ScratchRAMX		; 3 43 Restore the x register
	ldy ScratchRAMY		; 3 46 Restore the y register
 
	
NoChanges:	
	;SLEEP 30something

Edited by BNE Jeff
Link to comment
Share on other sites

Self modifying code is very useful. I've done it many times myself as have others.

 

In your example there does not seem to be many different values, and maybe you are doing too much for what you need. Have you considered just indexing like the example below, not running in ram?

 


    ldy    siIndex
    lda    SiLineTab,Y
    cmp    scanline
    bne    .skipUpdate
    lda    RegValTab,Y
    ldx    RegIndexTab,Y
    sta    0,X
.skipUpdate:



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RegIndexTab:
    .byte COLUP0
    .byte GRP0
    .byte ENABL
    .byte HMP1
    
RegValTab:
    .byte 0
    .byte YELLOW
    .byte %10101010
    .byte $02
    
SiLineTab:
    .byte 0
    .byte 131
    .byte 110
    .byte 108
Alternatively, you could also stick the look up tables in ram, and keep the routine in rom. If you are limited on ram and have lots of cycles then just keep the next value from each table to be used in ram (1 byte per table).
  • Like 1
Link to comment
Share on other sites

Thanks!

 

 

It looks like that saves me 5 cycles.. Does this look right?



	stx ScratchRAMX		; 3 3 Borrow the x register for register offset
	sty ScratchRAMY		; 3 6 Borrow the y register for data table offset
	
	; Test to see if there are any register changes on this line
	
	ldy SIIndex		; 3 9 y is the data table offset	
	lda SILineNum,y		; 4 13
	; lda ScanLine		;
	cmp ScanLine		; 3 16 See if it matches the stored next line to be changed
				; The first one of these will have to be seeded before the kernel
	bne NoChanges		; 2,3 18,19 If not skip over the change routine

	; if this line has a register change ; 8
	

	ldx SIRegister,y	; 4 22 x is an offset that matches registers (0,x)
	lda SIValue,y		; 4 26 load the value that will go in the register
	sta $0,x		; 4 30 store the operand in the register
	
	; Now update where for next change will happen
	
	;lda SINext,y		;  Load the next line number that will receive an update
	;sta SILineNumRAM	;  Store it where it will be compared to Scanline later
	inc SIIndexRAM		; 5 35 This will be the next table offset.

	ldx ScratchRAMX		; 3 38 Restore the x register
	ldy ScratchRAMY		; 3 41 Restore the y register
 
	
NoChanges:	
	;SLEEP 30something

Link to comment
Share on other sites

Sidenote: running code from cartridge RAM is a different topic, though: the SARA-RAM is too slow and can't handle being accessed on two back-to-back cycles, like lda #$00. CommaVid RAM does work though, since it's the main cause of the CommaVid cartridge. Wanted to try this one in a demo, if only I had more time...

  • Like 2
Link to comment
Share on other sites

I remember reading documentation on SARA stating that it can handle 300kHz.

Roughly calculated: 4 cycles per byte, so that's why LDA $F080 : LDA $F081 should work.

Never verified it due to not having access to the hardware (in "development form")

  • Like 1
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...