After running the accumulator and the memory location $1000 will contain Hex 14, Decimal 20.
LDA#10 ADC#10 STA $1000Top
After running the accumulator and the memory location $1000 will contain Hex FE, Decimal 20, Binary 11111111, which is -1 in 2's complement
SEC LDA#10 SBC#11 STA $1000Top
When run from location $1500, writes the text Hello World to the character based screen.
.ORG $1000 .BYTE "HELLO WORLD' .ORG $1500 LDX#0 LOOP: LDA $1000,X STA $C000,X LDA#1 STA $C8C1,X INX CPX#11 BNE LOOP: KILTop
This installs an interupt handler at $F100 which is the default location for interrupts. This handler simply checks for a keyboard interrupt and returns. The main part of the pogram is an infinite loop. When executed from location $1000, if you move to the VDU tab, click on the character screen and press keys so will see the time in the Interupt handler (Int) start to increase.
; Keyboard I/O Locations .VAR KEYBOARD=$F000 .ORG $1000 CLI ; Clear Interrupt Disable so we can handle interrupts OSLOOP: JMP OSLOOP: ; ---------SERVICE ROUTINES------------------------------------------------------------------- .ORG $F100 PHA TXA TSX PHA INX INX LDA $100,X ; get the status register from the stack AND #$10 ; mask B flag BNE BREAK: BEQ IRQ: BREAK: KIL ; For Program interrupts default to stopping. IRQ: ; Is this a keyboard interupt LDA KEYBOARD BEQ END: ; Handle keyboard interrupt ; We can do something here to handle a keystroke at the moment we simply return to the main routine END: PLA TAX PLA CLI ; Start servicing interrupts RTI ; Normal return from interrupt ; ---------- End Service Routines ----------------------------------Top
This installs an interupt handler at $F100 which is the default location for interrupts.This handler adds the keys to a buffer and the main loops processes them and adds them to the character based screen. If executed from location $1000 you can type on the character based screen as if it were a console window.
; Keyboard I/O Locations .VAR KEYBOARD=$F000 .VAR SCANCODE=$F001 .VAR KEY=$F002 .VAR KEYBUFFERSTART=$F040 .VAR KEYBBUFFERWRITEPOS=$24 .VAR KEYBBUFFERREADPOS=$26 .VAR TIMER1=$50 .VAR KEYBSIZEOFBUFFER=10 ; Video Location .VAR CHARACTERSTARTLOCATION=$C000 .VAR COLORSTARTLOCATION=$C8C1 .VAR CURX=$CF02 .VAR CURY=$CF03 .VAR SCREENSTART=$20 .VAR SCREENMEMLO=$00 .VAR SCREENMEMHI=$C0 .VAR ATTRSTART=$22 .VAR ATTRMEMLO=$C1 .VAR ATTRMEMHI=$C8 .VAR COLUMNS=80 .VAR LINES=22 .ORG $1000 CLI ; Clear Interrupt Disable so we can handle interrupts ; My first operating system MIKIX :-) ; Set up the cursor LDA#1 STA CURX STA CURY ; SETUP VDU location indexer in zeropage LDA#SCREENMEMLO STA SCREENSTART LDA#SCREENMEMHI STA SCREENSTART+1 LDA#ATTRMEMLO STA ATTRSTART LDA#ATTRMEMHI STA ATTRSTART+1 OSLOOP: ; Is there a keystroke in the buffer LDX KEYBBUFFERREADPOS CPX KEYBBUFFERWRITEPOS BEQ OSLOOP: ; If the read and write values are the same then there is no keyboard input LDY#0 ; Y register must be zero as we use it in the indexing LDA KEYBUFFERSTART, X ; Load the key pressed into the acculumator STA (SCREENSTART),Y ; Store the accumulator in the correct location in screen memory ; Increment screen memory pointer to point to the next location CLC LDA SCREENSTART ADC#1 STA SCREENSTART LDA#0 ADC SCREENSTART+1 STA SCREENSTART+1 LDA#31 ; Load the accumator with 31 (Foreground is white, background is blue) STA (ATTRSTART),Y ; Store the accumulator in the correct location in screen memory ; Increment attribute memory pointer to point to the next location CLC LDA ATTRSTART ADC#1 STA ATTRSTART LDA#0 ADC ATTRSTART+1 STA ATTRSTART+1 JSR CURSORMOVE: ; Move the read pointer to the next position in the keyboard buffer INC KEYBBUFFERREADPOS ; Increment the buffer position to point to the next slot CPX #KEYBSIZEOFBUFFER ; See if we are at the end of the buffer BNE OSLOOP: LDA#0 STA KEYBBUFFERREADPOS ; Reset the write buffer to the start JMP OSLOOP: ; ---------SUBROUTINES----------------------------------------------------------------------- CURSORMOVE: ; Move the cursor wrapping if necessary LDA CURX CMP#COLUMNS BEQ MOVENEXTLINE: INC CURX JMP CURSORMOVEEND: MOVENEXTLINE: LDA#1 ; First column STA CURX ; Check we are not at the end of the screen LDA CURY CMP#LINES BEQ MOVETOTOP: INC CURY JMP CURSORMOVEEND: MOVETOTOP: LDA#1 ; First row STA CURY CURSORMOVEEND: RTS ; ---------END SUBS--------------------------------------------------------------------------- ; ---------SERVICE ROUTINES------------------------------------------------------------------- .ORG $F100 PHA TXA TSX PHA INX INX LDA $100,X ; get the status register from the stack AND #$10 ; mask B flag BNE BREAK: BEQ IRQ: BREAK: KIL ; For Program interrupts default to stopping. IRQ: ; Is this a keyboard interupt LDA KEYBOARD BEQ END: ; Handle keyboard interrupt LDX KEYBBUFFERWRITEPOS ; Load the X register with the buffer offset LDA KEY ;load the key pressed into the accumulator BEQ END: ;Ignore zero which is unmapped keys STA KEYBUFFERSTART, X ; Store the key in the correct slot INC KEYBBUFFERWRITEPOS ; Increment the buffer position to point to the next slot CPX #KEYBSIZEOFBUFFER ; See if we are at the end of the buffer BNE BUFFERNOTFULL: LDA#0 STA KEYBBUFFERWRITEPOS ; Reset the write buffer to the start BUFFERNOTFULL: LDA #0 ;Handling of keyboard interrupt is complete so clear the flag STA KEYBOARD END: PLA TAX PLA CLI ; Start servicing interrupts RTI ; Normal return from interrupt ; ---------- End Service Routines ----------------------------------Top
This animates a space invader across the bitmap based screen using a timer to smooth this out. You should switch to the VDU page, select the bitmap screen and run from location $2000.
.VAR SPRITE1START=$0500 .VAR VRAM=$3000 .VAR TIMERLOCATION=$F003 .VAR TIMERDELAY=10 .VAR HardwareClearScreen = $08; .VAR XRES=160 .VAR SPRITEWIDTH=5; Width is 10 and 1 byte holds 2 pixels .VAR FROMLOC = 10 .VAR TOLOC = 12 .VAR SIZELOC=14 .VAR ROWSLOC=16 .ORG 16 .BYTE 10 .ORG $500 ; SPRITE 1 .BYTE $00,$06,$66,$60,$00,$06,$66,$66,$66,$60,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66 .BYTE $06,$66,$60,$66,$66,$66,$66,$66,$66,$00,$66,$00,$66,$00,$06,$00,$00,$00,$60,$60 .BYTE $00,$00,$00,$06 .ORG $2000 ;Show First Sprite moving a row of pixels at a time ; Move LDA#SPRITEWIDTH ;Lo STA SIZELOC LDA#0 ;Hi STA SIZELOC+1 .VAR VRAMOFFSET=0 .VAR VRAMOFFSETLOC=$60 .VAR MAXSPRITEMOVE=100 LDA#VRAMOFFSET STA VRAMOFFSETLOC INVADERLOOP: ; Start location of row x of the pixel LDA#SPRITE1START< STA FROMLOC LDA#SPRITE1START> STA FROMLOC+1 ; Start screenmem ; Add in the VRAMOFFSET CLC LDA#VRAM< ADC VRAMOFFSETLOC STA TOLOC LDA#VRAM> ADC #0 STA TOLOC+1 SPRITELOOP: JSR MOVEMEM: ; Increase the data locaction for the sprite CLC LDA FROMLOC ADC#SPRITEWIDTH STA FROMLOC LDA#0 ADC FROMLOC+1 STA FROMLOC+1 ; Increase by the screen width to go to the next row CLC LDA TOLOC ADC#XRES STA TOLOC LDA#0 ADC TOLOC+1 STA TOLOC+1 ; Keep looping till all rows displayed DEC ROWSLOC LDA ROWSLOC BNE SPRITELOOP: JSR WAIT: ;TODO Clear Screen LDA#1 STA HardwareClearScreen CHECKCLEAR: LDA HardwareClearScreen BNE CHECKCLEAR: ;Increment sprite location LDA VRAMOFFSETLOC ADC#1 STA VRAMOFFSETLOC CMP#MAXSPRITEMOVE ; JUMP BACK TO THE START IF THERE IS MORE ANIMATIONS BNE INVADERLOOP: TEMP: JMP TEMP: WAIT: LDA #TIMERDELAY STA TIMERLOCATION WAITLOOP: LDA TIMERLOCATION BNE WAITLOOP: RTS MOVEMEM: LDY #0 LDX SIZELOC+1 ; High byte of size BEQ MD2: MD1: LDA (FROMLOC),Y ; move a page at a time STA (TOLOC),Y INY BNE MD1: INC FROMLOC+1 INC TOLOC+1 DEX BNE MD1: MD2: LDX SIZELOC ; Low byte of size BEQ MD4: MD3: LDA (FROMLOC),Y ; move the remaining bytes STA (TOLOC),Y INY DEX BNE MD3: MD4: RTSTop