From 50ccc25f058a6817a391328f700fa679e6f0febf Mon Sep 17 00:00:00 2001 From: cuz Date: Thu, 13 Sep 2001 15:27:19 +0000 Subject: [PATCH] Redesigned the IRQ and BREAK logic, debugged the mouse routines git-svn-id: svn://svn.cc65.org/cc65/trunk@898 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- libsrc/c128/README | 6 ++ libsrc/c128/break.s | 66 +++++++--------- libsrc/c128/c128.inc | 1 + libsrc/c128/crt0.s | 114 ++++++++++++++++++++++----- libsrc/c128/mouse.s | 178 ++++++++++++++++++++++++------------------- 5 files changed, 229 insertions(+), 136 deletions(-) create mode 100644 libsrc/c128/README diff --git a/libsrc/c128/README b/libsrc/c128/README new file mode 100644 index 000000000..a1af61742 --- /dev/null +++ b/libsrc/c128/README @@ -0,0 +1,6 @@ +Implementation notes: + +CONDES routines with a type code of 2 are used to implement interrupt +handlers. Note that these are called as soon as the program is started, +so they have to cope with this. + diff --git a/libsrc/c128/break.s b/libsrc/c128/break.s index 6f4cfe420..0ecdc85ec 100644 --- a/libsrc/c128/break.s +++ b/libsrc/c128/break.s @@ -8,7 +8,8 @@ .export _set_brk, _reset_brk .destructor _reset_brk .export _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc - .importzp ptr1 + .import BRKStub, BRKOld, BRKInd + .importzp ptr1 .include "c128.inc" @@ -20,18 +21,11 @@ _brk_y: .res 1 _brk_sr: .res 1 _brk_pc: .res 2 -oldvec: .res 2 ; Old vector - - .data -uservec: jmp $FFFF ; Patched at runtime +uservec: jmp $FFFF ; Patched at runtime .code -; Where will we put the break stub? -stub_addr = $0E00 ; BASIC sprite area - - ; Set the break vector .proc _set_brk @@ -39,26 +33,26 @@ stub_addr = $0E00 ; BASIC sprite area sta uservec+1 stx uservec+2 ; Set the user vector - lda oldvec - ora oldvec+1 ; Did we save the vector already? - bne L2 ; Jump if we installed the handler already + lda BRKOld+1 + ora BRKOld+2 ; Did we save the vector already? + bne @L1 ; Jump if we installed the handler already - lda BRKVec - sta oldvec + lda BRKVec ; Save the old vector + sta BRKOld+1 lda BRKVec+1 - sta oldvec+1 ; Save the old vector + sta BRKOld+2 + + lda #BRKStub + sta BRKVec + stx BRKVec+1 - ldy #stub_size-1 ; Copy our stub into the low mem area -L1: lda brk_stub,y - sta stub_addr,y - dey - bpl L1 + lda #brk_handler + sta BRKInd+1 + stx BRKInd+2 -L2: lda #stub_addr - sta BRKVec+1 - rts +@L1: rts .endproc @@ -66,12 +60,14 @@ L2: lda #$C000 - sta sp+1 + lda #<(__RAM_START__ + __RAM_SIZE__) + sta sp + lda #>(__RAM_START__ + __RAM_SIZE__) + sta sp+1 ; Set argument stack ptr ; Call module constructors @@ -102,17 +111,43 @@ L1: lda sp,x jsr initconio +; If we have IRQ functions, chain our stub into the IRQ vector + + lda #<__IRQFUNC_COUNT__ + beq NoIRQ1 + lda IRQVec + ldx IRQVec+1 + sta IRQInd+1 + stx IRQInd+2 + lda #IRQStub + sei + sta IRQVec + stx IRQVec+1 + cli + ; Pass an empty command line - jsr push0 ; argc - jsr push0 ; argv +NoIRQ1: jsr push0 ; argc + jsr push0 ; argv ldy #4 ; Argument size jsr _main ; call the users code -; Call module destructors. This is also the _exit entry. +; This is also the _exit entry. Reset the IRQ vector if we chained it. + +_exit: lda #<__IRQFUNC_COUNT__ + beq NoIRQ2 + lda IRQInd+1 + ldx IRQInd+2 + sei + sta IRQVec + stx IRQVec+1 + cli + +; Run module destructors -_exit: jsr donelib ; Run module destructors +NoIRQ2: jsr donelib ; Reset the conio stuff @@ -120,9 +155,9 @@ _exit: jsr donelib ; Run module destructors ; Reset stack and the MMU - ldx spsave ; Patched at runtime + ldx spsave txs - lda mmusave ; Patched at runtime + lda mmusave sta MMU_CR ; Copy back the zero page stuff @@ -137,9 +172,52 @@ L2: lda zpsave,x jmp RESTOR +; ------------------------------------------------------------------------ +; The C128 has ROM parallel to the RAM starting from $4000. The startup code +; above will change this setting so that we have RAM from $0000-$BFFF. This +; works quite well with the exception of interrupts: The interrupt handler +; is in ROM, and the ROM switches back to the ROM configuration, which means +; that parts of our program may not be accessible. Since the crt0 module is +; the first module in the program, it will always be below $4000 and always +; in RAM. So we place several short stubs here that switch back our ROM +; config before calling our user defined handlers. These stubs are only +; used if any other code uses the interrupt or break vectors. They are dead +; code otherwise, but since there is no other way to keep them in low memory, +; they have to go here. + +IRQStub: + cld ; Just to be sure + lda MMU_CR ; Get old register value + pha ; And save on stack + lda #CC65_MMU_CFG ; Bank 0 with kernal ROM + sta MMU_CR + ldy #<(__IRQFUNC_COUNT__*2) + lda #<__IRQFUNC_TABLE__ + ldx #>__IRQFUNC_TABLE__ + jsr condes ; Call the functions + pla ; Get old register value + sta MMU_CR + jmp IRQInd ; Jump to the save IRQ vector + + +BRKStub: + pla ; Get original MMU_CR value + sta MMU_CR ; And set it + jmp BRKInd ; Jump indirect to break + + +; ------------------------------------------------------------------------ +; Data + .data zpsave: .res zpspace +; Old break vector preceeded by a jump opcode +BRKOld: jmp $0000 + +; Indirect vectors preceeded by a jump opcode +BRKInd: jmp $0000 + .bss spsave: .res 1 mmusave:.res 1 diff --git a/libsrc/c128/mouse.s b/libsrc/c128/mouse.s index 20a7b48a2..493d297fc 100644 --- a/libsrc/c128/mouse.s +++ b/libsrc/c128/mouse.s @@ -10,6 +10,7 @@ .export _mouse_box, _mouse_info .export _mouse_move, _mouse_pos .export _mouse_buttons, _mouse_info + .condes MouseIRQ, 2 .import _readjoy .import popa, popax, addysp1 @@ -39,10 +40,11 @@ XCORR = SPRITE_WIDTH ; unsigned char type); ; -_mouse_init: +.proc _mouse_init + jsr popa ; Ignore type and port - ldy OldIRQ+1 ; Already initialized? + lda Initialized ; Already initialized? bne AlreadyInitialized ; Jump if yes ; Initialize variables @@ -75,49 +77,53 @@ _mouse_init: sta XMax stx XMax+1 ; XMax = 320 + sprite width -; Remember the old IRQ vector +; Save the old init status and reset bit 0. This will disable the BASIC +; IRQ handler which will otherwise try to manage the mouse sprite on its +; own - lda IRQVec - sta OldIRQ - lda IRQVec+1 - sta OldIRQ+1 + lda INIT_STATUS + sta OldInitStatus + and #$FE + sta INIT_STATUS -; Set our own IRQ vector. We cheat here to save a few bytes of code: -; The function is expected to return a value not equal to zero on success, -; and since we know that the high byte of the IRQ handler address is never -; zero, we will return just this byte. +; Mouse successfully initialized - ldx #MouseIRQ - bne SetIRQ ; Branch always + lda #1 + sta Initialized + rts AlreadyInitialized: - lda #0 ; Error + lda #0 ; Error rts +.endproc + ; -------------------------------------------------------------------------- ; ; void mouse_done (void); ; -_mouse_done: - ldx OldIRQ ; Initialized? - lda OldIRQ+1 - beq Done ; Jump if no - ldy #0 - sty OldIRQ+1 ; Reset the initialized flag -SetIRQ: sei ; Disable interrupts - stx IRQVec ; Set the new/old vector - sta IRQVec+1 - cli ; Enable interrupts -Done: rts +.proc _mouse_done + + lda Initialized ; Initialized? + beq @L1 ; Jump if no + lda #0 + sta Initialized ; Reset the initialized flag + lda OldInitStatus ; Load the old BASIC int bit + and #$01 ; Mask it + ora INIT_STATUS ; Restore the old state + sta INIT_STATUS +@L1: rts + +.endproc ; -------------------------------------------------------------------------- ; ; void mouse_hide (void); ; -_mouse_hide: +.proc _mouse_hide + lda Invisible ; Get the flag bne @L1 ; Jump if already invisible @@ -130,12 +136,15 @@ _mouse_hide: @L1: inc Invisible ; Set the flag to invisible rts +.endproc + ; -------------------------------------------------------------------------- ; ; void mouse_show (void); ; -_mouse_show: +.proc _mouse_show + lda Invisible ; Mouse invisible? beq @L1 ; Jump if no dec Invisible ; Set the flag @@ -150,12 +159,15 @@ _mouse_show: @L1: rts +.endproc + ; -------------------------------------------------------------------------- ; ; void __fastcall__ mouse_box (int minx, int miny, int maxx, int maxy); ; -_mouse_box: +.proc _mouse_box + ldy #0 ; Stack offset add YCorr ; Adjust the Y value @@ -197,13 +209,16 @@ _mouse_box: jmp addysp1 ; Drop params, return +.endproc + ; -------------------------------------------------------------------------- ; ; void __fastcall__ mouse_pos (struct mouse_pos* pos); ; /* Return the current mouse position */ ; -_mouse_pos: +.proc _mouse_pos + sta ptr1 stx ptr1+1 ; Remember the argument pointer @@ -233,13 +248,15 @@ _mouse_pos: rts ; Done +.endproc + ; -------------------------------------------------------------------------- ; ; void __fastcall__ mouse_info (struct mouse_info* info); ; /* Return the state of the mouse buttons and the position of the mouse */ ; -_mouse_info: +.proc _mouse_info ; We're cheating here to keep the code smaller: The first fields of the ; mouse_info struct are identical to the mouse_pos struct, so we will just @@ -256,12 +273,15 @@ _mouse_info: rts +.endproc + ; -------------------------------------------------------------------------- ; ; void __fastcall__ mouse_move (int x, int y); ; -_mouse_move: +.proc _mouse_move + add YCorr ; Add Y coordinate correction bcc @L1 inx @@ -283,23 +303,32 @@ _mouse_move: rts +.endproc + ; -------------------------------------------------------------------------- ; ; unsigned char mouse_buttons (void); ; -_mouse_buttons: +.proc _mouse_buttons + lda #$00 ; Use port #0 jmp _readjoy ; Same as joystick +.endproc + ; -------------------------------------------------------------------------- ; ; Mouse interrupt handler -; +; + +IRQDone:rts MouseIRQ: - cld - lda SID_ADConv1 ; Get mouse X movement + + lda Initialized ; Mouse initialized? + beq IRQDone ; Jump if no + lda SID_ADConv1 ; Get mouse X movement ldy OldPotX jsr MoveCheck ; Calculate movement vector sty OldPotX @@ -364,14 +393,39 @@ MouseIRQ: @L4: sty YPos stx YPos+1 -; Move the mouse sprite if it is enabled +; Move the mouse sprite to the current mouse position. Must be called +; with interrupts off. MoveSprite1 is an entry without checking. + +MoveSprite: + + lda Invisible ; Mouse visible? + bne Done ; Jump if no + +; Set the high X bit + +MoveSprite1: + lda VIC_SPR_HI_X ; Get high X bits of all sprites + and #$FE ; Clear bit for sprite #0 + ldy XPos+1 ; Test Y position + beq @L5 + ora #$01 ; Set high X bit +@L5: sta VIC_SPR_HI_X ; Set hi X sprite values + +; Set the low X byte + + lda XPos + sta VIC_SPR0_X ; Set low byte - jsr MoveSprite ; Move the sprite +; Set the Y position -; Jump to the next IRQ handler + ldy YPos+1 ; Negative or too large? + bne Done ; Jump if yes + lda YPos + sta VIC_SPR0_Y ; Set Y position - jmp (OldIRQ) +; Done +Done: rts ; -------------------------------------------------------------------------- ; @@ -383,7 +437,8 @@ MouseIRQ: ; x/a = delta value for position ; -MoveCheck: +.proc MoveCheck + sty OldValue sta NewValue ldx #$00 @@ -409,50 +464,15 @@ MoveCheck: @L2: txa ; A = $00 rts -; -------------------------------------------------------------------------- -; -; Move the mouse sprite to the current mouse position. Must be called -; with interrupts off. MoveSprite1 is an entry without checking. -; - -MoveSprite: - - lda Invisible ; Mouse visible? - bne MoveSpriteDone ; Jump if no - -; Set the high X bit - -MoveSprite1: - lda VIC_SPR_HI_X ; Get high X bits of all sprites - and #$FE ; Clear bit for sprite #0 - ldy XPos+1 ; Test Y position - beq @L1 - ora #$01 ; Set high X bit -@L1: sta VIC_SPR_HI_X ; Set hi X sprite values - -; Set the low X byte - - lda XPos - sta VIC_SPR0_X ; Set low byte - -; Set the Y position - - ldy YPos+1 ; Negative or too large? - bne MoveSpriteDone ; Jump if yes - lda YPos - sta VIC_SPR0_Y ; Set Y position - -; Done - -MoveSpriteDone: - rts +.endproc ; -------------------------------------------------------------------------- ; Data .bss -OldIRQ: .res 2 ; Old IRQ vector +Initialized: .res 1 ; True if mouse initialized +OldInitStatus: .res 1 ; Old IRQ flag value OldValue: .res 1 ; Temp for MoveCheck routine NewValue: .res 1 ; Temp for MoveCheck routine YCorr: .res 1 ; Correction for Y coordinate -- 2.39.5