c64 assembly

Started by Amanda Dearheart, June 16, 2023, 02:53:41

Previous topic - Next topic

TomToad

Quote from: Baggey on June 19, 2023, 11:45:54Also,
Your line of CLI i think is incorrect.
I think as you've enabled interrupts with SEI, then set the address in memory. You then CLI, Clear the interrupt flag so the interrupt cant happen anyway ::).

You have that backwards.  SEI will SEt the Interrupt flag in the status register, and CLI will CLear the Interrupt flag.  When the interrupt flag is set, interrupts can't happen, so SEI effectively disables the interrupts and CLI will enable them.  Amanda has it correct in her code.  The two problems I see are that she has the byte order wrong, and in the actual interrupt (BORDER_SPARKLE$) should end with a RTI (ReTurn from Interrupt) instead of an RTS.

; ==============  MACROS  ===========
defm    RESET$
        LDA #/3
        STA /1
        STA /2
        endm

defm    CLEAR$
        LDA #$0093                      ;  ASCII 147 CLEAR THE SCREEN
        JSR CHROUT
        RTS
        endm
                     
defm    BORDER_SPARKLE$
        INC PEN_COLOR
        LDA PEN_COLOR
        CMP $0F
        BNE _exit
        LDA $00
        STA PEN_COLOR
_exit
        RTI  ; <--- Interrupts should end with RTI, not RTS
        endm

defm    INTR_SET$
        SEI                            ;  $0314 and $0315 store the mem address of the routine to point to
        LDA #/2                        ;  -> store the low byte first <-
        STA $0314
        LDA #/1                        ;  -> then store the high byte <-
        STA $0315
        CLI
        RTS
        endm
; -------------
------------------------------------------------
8 rabbits equals 1 rabbyte.

TomToad

Ok, looking closer, I am finding even more mistakes.  First of all, BORDER_SPARKLE$ is a macro, so doing >BORDER_SPARKLE$ and <BORDER_SPARKLE$ will not work as the > and < need an actual address attached to the label, macros are only code definitions, not actual code.  Also, I mentioned that an interrupt should end with RTI which is technically true, but if you are redirecting the IRQ vector, then your interrupt should JMP to the original vector address or else the C64 cannot do it's normal things like reading the keyboard.

There are a few other things as well, but I am having trouble getting CBM .prg Studio to behave the way I want it to.
------------------------------------------------
8 rabbits equals 1 rabbyte.

Steve Elliott

QuoteThe commodore 64 was the 2nd computer I ever purchased during the '80s. I had wanted to learn assembly then but didn't have the time, money, or space...and plan on buying the ZX Spectrum Next.  I also hear that there is a company planning on producing an Atari 800 xl that I'll buy.

Like other people on YouTube, I also feel nostalgic for the retro computing craze...the VIC-20 challenge. Since that only has 5k of ram, the purpose of this exercise is to see what type of game can be produced with that amount of memory.

Cool similar here, back in the day I never learnt Assembly Language. But now I'm learning ZX Spectrum/Spectrum Next/X64 Assembly Language, although I'm waiting on another Spectrum book so I don't go down any dead ends and have to re-write using 'better code'.

For the Spectrum Next search Ebay (and especially after the delivery of Kickstarter 2 Spectrum Nexts next month) and in the Next Shop (some spare Nexts will be available) around then: https://www.specnext.com/ The N-Go board is 100% compatible too and you can get them from various places like: https://store.activeconsult.co.uk/  Or here: https://manuferhi.com/p/n-go-full-include-wifi-rpi-zero 
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

dawlane

Quote from: TomToad on June 21, 2023, 11:50:06I am having trouble getting CBM .prg Studio to behave the way I want it to.
I've been playing around with it for around a day now; and it's not the best editor or built-in assembler.
Normally I would use something like Visual Studio code as an editor for assembler programming. But I suspect the appeal for this is the built-in tools for graphic's and SID.
So I thought I'd give C64Studio as go. Has the main tools apart from anything for the SID.

TomToad

Quote from: dawlane on June 24, 2023, 07:55:35
Quote from: TomToad on June 21, 2023, 11:50:06I am having trouble getting CBM .prg Studio to behave the way I want it to.
I've been playing around with it for around a day now; and it's not the best editor or built-in assembler.
Normally I would use something like Visual Studio code as an editor for assembler programming. But I suspect the appeal for this is the built-in tools for graphic's and SID.
So I thought I'd give C64Studio as go. Has the main tools apart from anything for the SID.

I only use CBM .PRG Studio because it has all the tools integrated together, such as a sprite editor, screen editor, etc...  I never really liked the way the assembler worked.  Was glad when they added Kick Assembler support, but I have yet to learn how to use it. A project I have made before using CBM .PRG Studio is a C64 version of Conway's Game Of Life.  Whereas most C64 versions run on a 40x25 grid, my version runs on an 80x50 grid.

I tried C64Studio before, but when I tried it, it was full of bugs.  Looking at it again, it appears that the bugs have been fixed, as well as some enhancements, so maybe I should try it out again.
------------------------------------------------
8 rabbits equals 1 rabbyte.

dawlane

#20
@Amanda Dearheart
OK. So the last time I did any real programming with a c64 was back in the 90's. So I would be rusty, but here is an example of using the interrupt to "sparkle" the border using CBM .prg Studio (not the best built-in assembler, text editor, or help. And has a few bugs that are ******* annoying).
You can study this to see where you were going wrong.

Start by creating a new Assembler Project. Uncheck the add Sprite and Char files. Set the title to sparkle and the source name to main.asm.
Paste this code into that file.
; Commodore 64 Border Interrupt Routine
; Sources to check out for information:
; https://codebase64.org/
; https://www.pagetable.com/?p=1397
; http://www.6502.org/
; Additional material can be found at https://commodore.software/downloads/category/184-reference-material
; Commodore 64 Whole Memory Guide - isbn: 0-86161-194-2
; Commodore Programmers Reference Guide - isbn: 0-672-22056-3
; Programming the Commodore 64: The Definitive Guide - isbn: 0-942386-50-7
; Commodore 64 Machine Language for the Absolute Beginner - isbn: 0-86161-145-4
;
; Using hardware interrupts for timing visual displays and reaction-time key interfacing on the commodore 64
; https://link.springer.com/article/10.3758/BF03202601
;
; Assembler tools used.
; C64 .prg Studio - https://www.ajordison.co.uk/

; ===================== MAIN ASSEMBLY FILE =====================

; Set the variable to replace in the BASIC ML loader with the start address.
export              entrypoint

; The main assembly will start at address 49152($0c00)
*=$c000

; Macros will be used for where code is to be repeated.
; NOTE: Macros are not functions. Any parameters passed are hard coded at compilation time.
; They should only be used in situations where it would be tedious to type repeated code over and over again.
entrypoint
                    sei                                     ; Disable IRQ
                    SET_CINV$ ROUTINE                       ; Set the hardware interrupts to point to the routine address.
                    RESET$                                  ; Insert the code to clear the screen and set the initial colours.
                    cli                                     ; Re-enable IRQ.
                    rts                                     ; return back to caller.
                   
PEN_COLOUR$         byte      $00                           ; Address to store the current colour.


; The code to execute when an IRQ is triggered.
ROUTINE
                    BORDER_SPARKLE$                         ; Insert the code to do a sparkle effect.
                    BORDER_BLACK$                           ; Insert the code to set the border colour to black.

; There are two ways in which to exit an interrupt. The first is to jump the the address that was originally in the CINV address.
; This pointed to the ROM routing located at $ea31. As this routine basically returns back to the basic editor, it slows down execution.
; The other is to use the return from interrupt (RTI). But to do this the registers need to be restored back to their original state.
                    ;jmp ROM_MAIN_IRQ_ENTRY_POINT$                   ; Uncomment to return to basic editor.

; Restore the CPU registers back.
; When in interrupt is triggered. A small bit of code is used to checked to see if the trigger was an IRQ or a BRK instruction.
; See $0314-$0315 (CINV) for details at https://www.pagetable.com/c64ref/c64mem/
                    pla
                    tay
                    pla
                    tax
                    pla
                    rti                                     ; return from interrupt.

In the section Assembly Files in the Project Explorer. Three files need to be created with the first being called: globalvalues.asm.
Paste the code below into it:
; ===================== GLOBAL VALUES ASSEMBLY FILE =====================

; SYSTEM COLOURS:
VIC_COLOUR_BLACK$ = $00
VIC_COLOUR_WHITE$ = $01
VIC_COLOUR_RED$ = $02
VIC_COLOUR_CYAN$ = $03
VIC_COLOUR_PURPLE$ = $04
VIC_COLOUR_GREEN$ = $05
VIC_COLOUR_BLUE$ = $06
VIC_COLOUR_YELLOW$ = $07
VIC_COLOUR_ORANGE$ = $08
VIC_COLOUR_BROWN$ = $09
VIC_COLOUR_LT_RED$ = $0a
VIC_COLOUR_DRK_GREY$ = $0b
VIC_COLOUR_GREY$ = $0c
VIC_COLOUR_LT_GREEN$ = $0d
VIC_COLOUR_LT_BLUE$ = $0e
VIC_COLOUR_LT_GREY$ = $0f

; ROM ROUTINES:
ROM_CLEAR_SCREEN$ = $e544
ROM_MAIN_IRQ_ENTRY_POINT$ = $ea31
ROM_CHROUT$ = $f1ca

The next assembly file is called memorymap.asm. Paste the code below.
; ===================== SYSTEM MEMORY MAP ASSEMBLY FILE =====================
; For full explanation. See Commodore 64 Whole Memory Guide.

; All common locations used should be defined as global variables
; PAGE 1 locations.
CINV$ = $0314                                                    ; Two bytes: Hardware interrupt vector address pointer.

; I/O Register locations.
VIC_CTRL_REG1$ = $d011                                           ; First of the two VIC-II control registers. Controls raster and display.
VIC_RASTER_RW_REG$ = $d012                                       ; Raster Read/Write register
VIC_CTRL_REG2$ = $d016                                           ; Second of the two VIC-II control registers. Controls multi-colour and display.
VIC_IRQ_FLAG_REG$ = $d019                                        ; VIC-II interrupt flag register.
VIC_IRQ_MASK_REG$ = $d01a                                        ; VIC-II interrupt mask register.
VIC_BORDER_COLOUR$ = $d020                                       ; Controls the colour of the border.
VIC_BACK_GROUND_COLOUR0$ = $d021                                 ; Controls the centre screen colour for both text and bitmap mode.

The last assembly file is called macro.asm. Paste the code below.
; ===================== MACRO ASSEMBLY FILE =====================
; NOTE: CBM .prg Studio's default assembler cannot use a macro within a macro, so defining a macros and then trying to
;       define it inside another macro will not work.
defm                SET_CINV$
                    lda       #</1
                    sta       CINV$
                    lda       #>/1
                    sta       CINV$+1
                    endm

defm                BORDER_SPARKLE$
                    inc       PEN_COLOUR$                   ; Increase the value stored in the address PEN_COLOUR.
                    lda       PEN_COLOUR$                   ; Load the accumulator with the value stored at PEN_COLOUR.
                    cmp       #VIC_COLOUR_LT_GREY$+1        ; Check for light grey plus one to make sure all colours are used.
                    bne       @skip                         ; If the status is not zero, then jump over the resetting of the address PEN_COLOUR
                    lda       #VIC_COLOUR_BLACK$            ; Load the accumulator register with the colour black
                    sta       PEN_COLOUR$                   ; Store the value in the accumulator into the address PEN_COLOUR.               
@skip               sta       VIC_BORDER_COLOUR$            ; Set the border colour to the value of PEN_COLOUR
                    endm

defm                BORDER_BLACK$
                    lda       #VIC_COLOUR_BLACK$            ; Load the accumulator register with the colour black
                    sta       VIC_BORDER_COLOUR$            ; Set the border colour to black.
                    endm

defm                RESET$
                    jsr       ROM_CLEAR_SCREEN$             ; Call the rom's clear screen routine.
                    lda       #VIC_COLOUR_BLACK$            ; Load the accumulator register with the colour black
                    sta       VIC_BORDER_COLOUR$            ; Set the border colour to black.
                    sta       VIC_BACK_GROUND_COLOUR0$      ; Set the main screen colour.
                    endm


The last file needs to be in the Basic Files section and is only one line long. Call this file sparkle and add the line:
10 SYS entrypoint

From the main menu select Project->Properties. And make sure that the Use specific build order in the Project Files section is selected. Click the Include all button and make sure that they are in this order:
globalvalues.asm
memorymap.asm
macro.asm
main.asm
sparkle.bas

The alternative to the build order is to create the files out side of CBM .prg Studio and add in the main.asm file this directives:
incasm              "globalvalues.asm"
incasm              "memorymap.asm"
incasm              "macro.asm"

But the build order for the project properties has to be assembly files and basic loader last.