|
Post by jfmateos on Dec 20, 2013 7:19:50 GMT -5
|
|
|
Post by jfmateos on Dec 20, 2013 9:42:51 GMT -5
|
|
|
Post by christophertumber on Jul 29, 2014 22:15:12 GMT -5
I realize this is an old thread, but, just FYI I wouldn't really recommend the OCD source code as a learning tool. It's fairly crude by modern standards and very unoptimized - does a lot of things I would never do now:
- Unoptimized BIOS routines - No Salomon draw wait state optimizations - Subroutines (and probably more)
I really suggest using the VFrogger source instead. VFrogger source is also quite well documented.
|
|
|
Post by jfmateos on Jul 29, 2014 23:37:43 GMT -5
Thank you very much christopher... every code is usefull for me now. I will also study VFrogger (I have already read the optimization notes about this game... it is very valuable information).
|
|
|
Post by cNp on Jul 30, 2014 7:24:45 GMT -5
I realize this is an old thread, but, just FYI I wouldn't really recommend the OCD source code as a learning tool. It's fairly crude by modern standards and very unoptimized - does a lot of things I would never do now: - Unoptimized BIOS routines - No Salomon draw wait state optimizations - Subroutines Hey Chris, As a relative newb to programming the Vectrex I use all the BIOS routines as is... at what point did you find you needed to write your own optimised versions? I guess as I write my games they will either be fine using BIOS routines or I'll hit a point where performance starts to suffer and optimising will have to begin! Are there any original BIOS routines you do still use due to them being optimal enough as is? Cheers, cNp
|
|
|
Post by christophertumber on Jul 30, 2014 8:18:36 GMT -5
OCD uses all BIOS routines.
VIX/TSUNAMI et all still use some BIOS routines, I think the joystick and button routines. Possibly the sound routines.
Specter and the other game I'm working on probably won't use any.
Even just inlining the BIOS routines unchanged saves you 13 cycles per use by eliminating JSR/RTS pairs. That may not seem like a lot, but, if you have 20 objects (including playfield, "sprites", shots, scores, &etc) on the screen and you eliminate a JSR/RTS for both a MOVE_PEN and DRAW_TO type routines each that saves 520 cycles which is probably enough to draw two (!) more objects. Basically for free (your ROM size does increase).
The biggest problem is the moving/drawing routines since using the BIOS routines means you can't recover the cycles spend waiting for the hardware.
I can understand wanting to use the BIOS routines to keep it simple and use them as black boxes where you just send parameters and don't care what they actually do while concentrating on learning other things. That's fine, but what I'd suggest you do take the BIOS routines you need and place them unchanged into Macros. Then use the Macro instead. Later you can always go into the Macro and optimize or customize to your needs.
Eliminating JSR/RTS is a cheap and easy way to start to optimize your code. And if you use Macros instead of subroutines you code remains quite readable even though modern coding standards would cry. In the end, you should have virtually no JSR/RTS in your code. About the only time I would ever use them is if they're large subroutines that get called a lot and inlining them would cause too much ROM bloat (or if you have cycles to spare, ie; simple title/intro screens and such). Though in that case you may be better off taking the hit on overhead from a loop. (You also generally want to avoid loops [in favour of Macros or repetitive code] because cycles).
Consider the following two code snippets. Both drawing an object with 4 vectors (a square because I needed some values but whatever). The first one takes 129 cycles more than the second. And all we've done to optimize is inline the BIOS routines and unroll the loop. That's 129 free cycles every time we draw a really simple shape (more for more complex shapes).
;Unoptimized ldx #Vector_List ;3 ldd ShipPosition ;6 jsr Move_Pen_D ;8+5 next_vector: ; Loop is 28 cycles (+BIOS) ldd ,x++ ;8 beq done_drawing ;3 jsr Draw_To_D ;8+5 jmp next_vector ;4 done_drawing: jsr reset0ref ;8+5
;Total cycles = 22+28*4+13+BIOS = 147+BIOS
;Optimized ldd ShipPosition ;6 MOVE_PEN_MACRO ldd #$7f00 ;3 DRAW_MACRO ldd #$007F ;3 DRAW_MACRO ldd #$8100 ;3 DRAW_MACRO ldd #$0081 ;3 DRAW_MACRO RESET0REF_MACRO
;Total cycles = 18+BIOS = 18+BIOS
|
|
|
Post by christophertumber on Jul 30, 2014 8:38:09 GMT -5
Cliff notes: If you don't care about optimization. If you're focused on learning assembly language and not so much Vectrex specifics. If you're just hacking around. Go ahead and use the BIOS routines. The only real reason to stop using them is for performance. However, once you start to "get serious" they're low hanging fruit as far as optimization. (There's certainly value in learning how to program the hardware directly but that's fairly advanced and optimization becomes a pressing issue far sooner).
|
|
|
Post by cNp on Jul 30, 2014 8:45:11 GMT -5
Awesome explanation, cheers Chris.
I generally inline my own code and avoid loops (as to some extent you don't have to worry too much about ROM size).
I think I will be using your macro idea to eliminate the JSRs.
cNp
|
|
|
Post by jfmateos on Jul 30, 2014 10:01:28 GMT -5
Nice Christopher... your explanation is very illustrative.
|
|
|
Post by christophertumber on Aug 3, 2014 12:58:19 GMT -5
FYI, this is the current main loop for the unnamed shooter I'm working on. It's about to change dramatically as I reorganize for optimization so I'm posting it now:
main: DPD0 ; jsr waitrecal WAITRECAL_MACRO
READ_SWITCHES_MACRO READ_JOYSTICK_MACRO
;------------------------------------------ ;Playfield Intensity5F Left_Wall Right_Wall
Setup_Draw_Horizontal0 Setup_Draw_Horizontal1 Setup_Draw_Horizontal2 Setup_Draw_Horizontal3 Setup_Draw_Horizontal4 Setup_Draw_Horizontal5 Setup_Draw_Horizontal6 Setup_Draw_Horizontal7 Setup_Draw_Horizontal8 Setup_Draw_Horizontal9 Setup_Draw_Horizontal10 Setup_Draw_Horizontal11 Setup_Draw_Horizontal12 Setup_Draw_Horizontal13 Setup_Draw_Horizontal14 Setup_Draw_Horizontal15
Setup_Draw_Vertical0 Setup_Draw_Vertical1 Setup_Draw_Vertical2 Setup_Draw_Vertical3 Setup_Draw_Vertical4 Setup_Draw_Vertical5 Setup_Draw_Vertical6 Setup_Draw_Vertical7 Setup_Draw_Vertical8 Setup_Draw_Vertical9 Setup_Draw_Vertical10 Setup_Draw_Vertical11 Setup_Draw_Vertical12 Setup_Draw_Vertical13 Setup_Draw_Vertical14
;------------------------------------------ ;Player and Shots
DPD0
Intensity7F
Draw_Player
STANDARD_SCALE Draw_Shot1 Draw_Shot2 Draw_Shot3 Draw_Shot4 Draw_Shot5 Draw_Shot6
;------------------------------------------ ;Moving ;Note: ;Up -> Right ;Left -> Up ;Right -> Down ;Down -> Left
DPC9 check_calibration
Move_Player Find_Player_Column Find_Player_Row Check_Player_Wall_Collision Check_Player_At_Edge ;------------------------------------------ ;Shooting
Player_New_Shot
Move_Player_Shot1 Move_Player_Shot2 Move_Player_Shot3 Move_Player_Shot4 Move_Player_Shot5 Move_Player_Shot6
Check_Shot_Wall_Collision1 Check_Shot_Wall_Collision2 Check_Shot_Wall_Collision3 Check_Shot_Wall_Collision4 Check_Shot_Wall_Collision5 Check_Shot_Wall_Collision6
Check_Shot_Edge1 Check_Shot_Edge2 Check_Shot_Edge3 Check_Shot_Edge4 Check_Shot_Edge5 Check_Shot_Edge6
jmp main
|
|
|
Post by jfmateos on Aug 3, 2014 13:21:31 GMT -5
Very tidy code... nice to read it
|
|
|
Post by Rapetou33 on Aug 14, 2014 12:15:02 GMT -5
Yes nice to view some concrete examples
|
|
|
Post by jfmateos on Dec 5, 2014 6:54:58 GMT -5
Dear christopher, I am trying to apply your macro advice to avoid JSR.... I had never before used macros. Please, could you show the code of the MOVE_PEN_MACRO? I don't know how to deal with the branchs inside the code of this subroutine. Moveto_d: STA <VIA_port_a ;Store Y in D/A register CLR <VIA_port_b ;Enable mux PSHS D ;Save D-register on stack LF318: LDA #$CE ;Blank low, zero high? STA <VIA_cntl CLR <VIA_shift_reg ;Clear shift regigster INC <VIA_port_b ;Disable mux STB <VIA_port_a ;Store X in D/A register CLR <VIA_t1_cnt_hi ;timer 1 count high PULS D ;Get back D-reg JSR Abs_a_b STB -1,S ORA -1,S LDB #$40 CMPA #$40 BLS LF345 CMPA #$64 BLS LF33B LDA #$08 BRA LF33D
LF33B: LDA #$04 ;Wait for timer 1 LF33D: BITB <VIA_int_flags BEQ LF33D LF341: DECA ;Delay a moment BNE LF341 RTS
LF345: BITB <VIA_int_flags ;Wait for timer 1 BEQ LF345 RTS OCD uses all BIOS routines. VIX/TSUNAMI et all still use some BIOS routines, I think the joystick and button routines. Possibly the sound routines. Specter and the other game I'm working on probably won't use any. Even just inlining the BIOS routines unchanged saves you 13 cycles per use by eliminating JSR/RTS pairs. That may not seem like a lot, but, if you have 20 objects (including playfield, "sprites", shots, scores, &etc) on the screen and you eliminate a JSR/RTS for both a MOVE_PEN and DRAW_TO type routines each that saves 520 cycles which is probably enough to draw two (!) more objects. Basically for free (your ROM size does increase). The biggest problem is the moving/drawing routines since using the BIOS routines means you can't recover the cycles spend waiting for the hardware. I can understand wanting to use the BIOS routines to keep it simple and use them as black boxes where you just send parameters and don't care what they actually do while concentrating on learning other things. That's fine, but what I'd suggest you do take the BIOS routines you need and place them unchanged into Macros. Then use the Macro instead. Later you can always go into the Macro and optimize or customize to your needs. Eliminating JSR/RTS is a cheap and easy way to start to optimize your code. And if you use Macros instead of subroutines you code remains quite readable even though modern coding standards would cry. In the end, you should have virtually no JSR/RTS in your code. About the only time I would ever use them is if they're large subroutines that get called a lot and inlining them would cause too much ROM bloat (or if you have cycles to spare, ie; simple title/intro screens and such). Though in that case you may be better off taking the hit on overhead from a loop. (You also generally want to avoid loops [in favour of Macros or repetitive code] because cycles). Consider the following two code snippets. Both drawing an object with 4 vectors (a square because I needed some values but whatever). The first one takes 129 cycles more than the second. And all we've done to optimize is inline the BIOS routines and unroll the loop. That's 129 free cycles every time we draw a really simple shape (more for more complex shapes). ;Unoptimized ldx #Vector_List ;3 ldd ShipPosition ;6 jsr Move_Pen_D ;8+5 next_vector: ; Loop is 28 cycles (+BIOS) ldd ,x++ ;8 beq done_drawing ;3 jsr Draw_To_D ;8+5 jmp next_vector ;4 done_drawing: jsr reset0ref ;8+5
;Total cycles = 22+28*4+13+BIOS = 147+BIOS
;Optimized ldd ShipPosition ;6 MOVE_PEN_MACRO ldd #$7f00 ;3 DRAW_MACRO ldd #$007F ;3 DRAW_MACRO ldd #$8100 ;3 DRAW_MACRO ldd #$0081 ;3 DRAW_MACRO RESET0REF_MACRO
;Total cycles = 18+BIOS = 18+BIOS
|
|
|
Post by jfmateos on Dec 5, 2014 7:20:27 GMT -5
Or more useful, could you help me with the Draw_VLc macro?
|
|
|
Post by jfmateos on Dec 5, 2014 7:28:25 GMT -5
Forget it Christopher.... i have found out how to do it. Thanks.
|
|