From b4bc2d9b75c7ecf39f26b717b88384b8a5a9f578 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Mon, 22 Feb 2016 14:56:05 -0500 Subject: more code shrinkage, 7356 bytes free --- Makefile | 2 +- console.s | 68 ++++++++++++++++++++++++- cprintul.s | 109 ++++++++++++++++++++++++++++++++++++++++ messages.pl | 2 +- taipan.c | 163 ++++++++++++++++++++++++++++++++++++++++-------------------- 5 files changed, 287 insertions(+), 57 deletions(-) create mode 100644 cprintul.s diff --git a/Makefile b/Makefile index 6d46230..f852219 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,7 @@ XEX=taipan.xex # All the C and asm sources for taimain.xex: TAIMAIN_HDRS=sounds.h TAIMAIN_C_SRC=taipan.c strtonum.c -TAIMAIN_ASM_SRC=rand.s draw_lorcha.s timed_getch.s portstat.s console.s ultostr.s soundasm.s explosion.s textdecomp.s +TAIMAIN_ASM_SRC=rand.s draw_lorcha.s timed_getch.s portstat.s console.s cprintul.s soundasm.s explosion.s textdecomp.s TAIMAIN_LIBS=conio/conio.lib # Comment these lines out to build without big number support. diff --git a/console.s b/console.s index b02403d..7837ce1 100644 --- a/console.s +++ b/console.s @@ -1,7 +1,7 @@ .include "atari.inc" - .export _clrtobot, _clrtoeol, _clr_screen, _clrtoline, _cspaces, _cblank, _backspace + .export _clrtobot, _clrtoeol, _clr_screen, _clrtoline, _cspaces, _cblank, _backspace, _cprint_pipe, _cprint_bang, _cspace, _cputc_s, _comma_space, _cprint_colon_space, _cprint_question_space, _cprint_period, _cprint_taipan_prompt .export _rvs_on, _rvs_off .import mul40 ; from cc65's runtime @@ -9,7 +9,8 @@ .import _revflag ; conio/revers.s .import bump_destptr ; these two are .importzp destptr ; from draw_lorcha.s - .import _cspace + .importzp sreg + .import _cprintulong, _cputc, _cprint_taipan .ifdef CART_TARGET .segment "HIGHCODE" @@ -117,3 +118,66 @@ _rvs_off: lda #0 sta _revflag rts + + ; micro-optimizations here. + ; the stuff below might be a bit hard to follow, but it saves code. + ; calling this: cputs("? "); + ; emits code like this: + ; lda #Lxxx + ; jsr _cputs + ; ...which is 9 bytes per call (plus 3 bytes for the "? " string itself). + ; replacing each cputs("? "); with cprint_question_space() means 3 bytes + ; per call (a JSR). there are 3 'some char followed by a space' routines + ; here, totalling 10 bytes. the actual space is printed by code shared + ; with cspace(). + ; also, there are 5 'print a single character' routines. each one would + ; normally be cputc('X'), which compiles to: + ; lda #'X' + ; jsr _cputc + ; ...or 5 bytes each. we have 5 of them, so 25 bytes. using fall-thru + ; and the BIT trick, they condense down to 17 bytes. + ; if you're not familiar with the "BIT trick" to skip a 2-byte instruction, + ; the stuff below looks like gibberish, sorry. + + ; ", Taipan? " + ; using fall-thru here saves 3 bytes (normally the last instruction + ; would be "jmp _cprint_question_space") +_cprint_taipan_prompt: + jsr _comma_space + jsr _cprint_taipan + ; fall thru + + ; each entry point here prints one character followed by a space + ; "? " +_cprint_question_space: + lda #'?' + .byte $2c + + ; ": " +_cprint_colon_space: + lda #':' + .byte $2c + + ; ", " +_comma_space: + lda #',' + jsr _cputc + ; fall thru + + ; each entry point here prints one character +_cspace: + lda #' ' + .byte $2c +_cprint_pipe: + lda #'|' + .byte $2c +_cputc_s: + lda #'s' + .byte $2c +_cprint_period: + lda #'.' + .byte $2c +_cprint_bang: + lda #'!' + jmp _cputc diff --git a/cprintul.s b/cprintul.s new file mode 100644 index 0000000..cf90574 --- /dev/null +++ b/cprintul.s @@ -0,0 +1,109 @@ +; cprintul.s - print an unsigned long, int, or char + +; Modified from cc65's libsrc/common/ltoa.s +; Originally by Ullrich von Bassewitz, 11.06.1998 + +; modified version by B. Watson + +; - print the characters with cputs instead of storing in a buffer +; - rename ultoa => cprintul, change its prototype +; - add cprintuchar and cprintuint wrappers +; - got rid of ltoa (don't need it) +; - hardcode radix to 10 +; - don't need __hextab since we don't do hex (saves 16 bytes) +; - get rid of dopop subroutine, since the return type is now +; void, and we don't take a buffer argument that needs returning. + +; void __fastcall__ cprintul(unsigned long value); + + .export _cprintulong, _cprintuchar, _cprintuint + .import popax, _cputc + .importzp sreg, ptr2 + +radix = 10 + + .ifdef CART_TARGET + .segment "HIGHCODE" + .else + .code + .endif + + ; char and int wrappers for cprintulong(). basically these are + ; the 'casting' code cc65 would emit any time cprintulong() is + ; called with a char or int argument. it happens often enough in + ; taipan.c that it's worth doing this way: + + ; cprintulong(1) compiles to 11 bytes: + ; ldx #$00 + ; stx sreg + ; stx sreg+1 + ; lda #$01 + ; jsr _cprintulong + + ; whereas cprintuchar(1) is 5 bytes (saves 6): + ; lda #$01 + ; jsr _cprintuchar + + ; cprintuint(1) is 7 bytes (saves 4, add 'ldx #$00' to the above). + + ; the wrappers are 10 bytes together. so long as we remember to *use* + ; them, we only have to use cprintuchar() 2 times and/or cprintuint() + ; 3 times to start saving bytes. + +_cprintuchar: + ldx #0 +_cprintuint: + pha + lda #0 + sta sreg + sta sreg+1 + pla + + ; main routine +_cprintulong: + ; high word passed to us in sreg + ; low word in ptr2 + sta ptr2 + stx ptr2+1 + +; Convert to string by dividing and push the result onto the stack + + lda #$00 + pha ; sentinel + +; Divide val/radix -> val, remainder in a + +L5: ldy #32 ; 32 bit + lda #0 ; remainder +L6: asl ptr2 + rol ptr2+1 + rol sreg + rol sreg+1 + rol a + cmp #radix + bcc L7 + sbc #radix + inc ptr2 +L7: dey + bne L6 + + ora #'0' ; get ascii character + pha ; save char value on stack + + lda ptr2 + ora ptr2+1 + ora sreg + ora sreg+1 + bne L5 + +; Get the characters from the stack, print them. + +@print: pla + beq @done ; exit if sentinel + pha + jsr _cputc + pla + bne @print ; branch always + +@done: + rts diff --git a/messages.pl b/messages.pl index ad53d87..65ade0f 100644 --- a/messages.pl +++ b/messages.pl @@ -48,6 +48,7 @@ print "// ratio: " . sprintf("%.1f", $total_out * 100 / $total_in) . illion "illion" # somehow this wastes 2 bytes fine "fine" run "Run" # too short to be worth compression +how_much_spc "How much " =cut __END__ @@ -67,7 +68,6 @@ saigon "Saigon" manila "Manila" singapore "Singapore" batavia "Batavia" -how_much_spc "How much " will_you "will you " bad_joss "Bad Joss!!\r\n" crlf "\n" diff --git a/taipan.c b/taipan.c index 7531ada..e221fc5 100644 --- a/taipan.c +++ b/taipan.c @@ -117,6 +117,19 @@ extern void clrtoeol(void); /* print 'count' spaces: */ extern void __fastcall__ cspaces(unsigned char count); +/* each prints one specific character */ +extern void cspace(void); +extern void cputc_s(void); +extern void cprint_bang(void); +extern void cprint_pipe(void); +extern void cprint_period(void); + +/* each print 2 characters */ +extern void comma_space(void); +extern void cprint_question_space(void); +extern void cprint_colon_space(void); +extern void cprint_taipan_prompt(void); + /* our own clr_screen(), don't use conio's clrscr() */ extern void clr_screen(void); @@ -182,14 +195,18 @@ unsigned char one_chance_in(unsigned char odds) { } /* print 1 space */ +/* void cspace(void) { cputc(' '); } +*/ /* print the letter s (for pluralization) */ +/* void cputc_s(void) { cputc('s'); } +*/ /* print 'count' spaces, but leave the cursor where it was. been rewritten in asm, see console.s */ @@ -273,7 +290,11 @@ void retire(void); void final_stats(void); void you_only_have(unsigned char in_bank); -void cprintulong(unsigned long ul); +/* these 3 are from cprintul.s */ +extern void cprintulong(unsigned long ul); +extern void cprintuint(unsigned int ui); +extern void cprintuchar(unsigned char uc); + void cprintfancy(unsigned long num); void cprintfancy_centered(unsigned long num); void too_much_cash(void); @@ -414,9 +435,15 @@ long damage = 0, capacity = 60, newdamage; there are diminishing returns. Anything that only occurs twice might or might not be worth turning into a function. */ +#ifdef CART_TARGET +# pragma code-name (push, "HIGHCODE") +#endif + void how_much(void) { // cputs("How much "); - print_msg(M_how_much_spc); + // print_msg(M_how_much_spc); + print_msg(M_how_much); + cspace(); } void how_much_will_you(void) { @@ -440,24 +467,29 @@ void cprint_taipan(void) { print_msg(M_taipan); } +/* void comma_space(void) { cputs(", "); } +*/ void cprint_taipan_comma(void) { cprint_taipan(); comma_space(); } +/* void cprint_colon_space(void) { cputs(": "); } +*/ void cprint_taipan_colon(void) { cprint_taipan(); cprint_colon_space(); } +/* void cprint_bang(void) { cputc('!'); } @@ -465,6 +497,7 @@ void cprint_bang(void) { void cprint_pipe(void) { cputc('|'); } +*/ void cprint_taipan_bang(void) { comma_space(); @@ -480,18 +513,23 @@ void cprint_taipan_bangbang(void) { void cprint_taipan_period(void) { comma_space(); cprint_taipan(); - cputc('.'); + // cputc('.'); + cprint_period(); } + /* void cprint_question_space(void) { cputs("? "); } +*/ +/* void cprint_taipan_prompt(void) { comma_space(); cprint_taipan(); cprint_question_space(); } +*/ void do_you_wish(void) { // cputs("do you wish "); @@ -524,6 +562,9 @@ void cprint_firm_colon(void) { char get_ship_status(void) { return 100 - ((damage * 100L) / capacity); } +#ifdef CART_TARGET +# pragma code-name (pop) +#endif #ifdef BIGNUM bignum(big1T) = BIG_1T; @@ -587,9 +628,11 @@ void cprintfancy_big(bignump b) { cprintulong(leftdigits); if(rightdigits) { - cputc('.'); + // cputc('.'); + cprint_period(); if(leading0) cputc('0'); - cprintulong((unsigned long)rightdigits); + // cprintulong((unsigned long)rightdigits); + cprintuchar(rightdigits); } if(letter) { @@ -601,14 +644,20 @@ void cprintfancy_big(bignump b) { } #endif +#ifdef CART_TARGET +# pragma code-name (push, "HIGHCODE") +#endif + int get_time(void) { return ((year - 1860) * 12) + month; } /* print an int or long as a string, conio-style */ +/* void cprintulong(unsigned long ul) { cputs(ultostr(ul, num_buf)); } +*/ void at_sea(void) { gotoxy(30, 6); @@ -659,6 +708,10 @@ void overload(void) { unsigned int gunamt(void) { return randi()%(1000 * (get_time() + 5) / 6); } +#ifdef CART_TARGET +# pragma code-name (pop) +#endif + void new_ship(void) { unsigned long amount; @@ -679,7 +732,7 @@ void new_ship(void) { } // cputs("\r\nship for one with 50 more capacity by\r\npaying an additional "); print_msg(M_ship_for_one); - cprintulong(50); + cprintuchar(50); print_msg(M_more_capacity); cprintfancy(amount); cprint_taipan_prompt(); @@ -778,7 +831,8 @@ void cprintfancy(unsigned long num) { tmp = (num % 1000000L) / 100000L; cprintulong(num / 1000000L); if(tmp) { - cputc('.'); + // cputc('.'); + cprint_period(); cprintulong(tmp); } } else if (num >= 1000000L) { @@ -789,7 +843,8 @@ void cprintfancy(unsigned long num) { tmp = (num % 1000000L) / 10000L; cprintulong(num / 1000000L); if(tmp) { - cputc('.'); + // cputc('.'); + cprint_period(); if(tmp < 10L) cputc('0'); cprintulong(tmp); } @@ -817,19 +872,8 @@ void justify_int(unsigned int num) { if(num < 1000) cspace(); if(num < 100) cspace(); if(num < 10) cspace(); - cprintulong(num); -} -#ifdef CART_TARGET -# pragma code-name (pop) -#endif - -/* -void hide_cursor() { - gotoxy(0,23); - cspace(); + cprintuint(num); } -*/ - void update_guns() { rvs_on(); gotoxy(31, 1); @@ -866,17 +910,6 @@ void fight_stats(int ships, int orders) { default: break; } - /* - // switch() saves 15 bytes over this: - if(orders == 1) - cputs("Fight"); - else if(orders == 2) - cputs("Run"); - else if(orders == 3) - cputs("Throw Cargo"); - */ - - // hide_cursor(); } /* print an inverse video plus if there are offscreen ships, @@ -897,6 +930,10 @@ void set_orders(void) { } } +#ifdef CART_TARGET +# pragma code-name (pop) +#endif + /* sea_battle only ever returns 1 to 4. making the return type a char saved 61 bytes! */ char sea_battle(char id, int num_ships) { @@ -967,7 +1004,7 @@ char sea_battle(char id, int num_ships) { print_msg(M_cur_seaworth); cputs(st[status / 20]); cputs(" ("); - cprintulong(status); + cprintuchar(status); cputs("%)"); gotoxy(0, 4); @@ -1095,7 +1132,7 @@ char sea_battle(char id, int num_ships) { if(sk > 0) { // cputs("Sunk "); print_msg(M_sunk); - cprintulong(sk); + cprintuint(sk); // cputs(" of the buggers"); print_msg(M_of_the_buggers); cprint_taipan_bang(); @@ -1117,7 +1154,7 @@ char sea_battle(char id, int num_ships) { fight_stats(num_ships, orders); gotoxy(0, 3); clrtoeol(); - cprintulong(ran); + cprintuint(ran); // cputs(" ran away"); print_msg(M_ran_away); cprint_taipan_bang(); @@ -1285,7 +1322,7 @@ char sea_battle(char id, int num_ships) { clrtoeol(); // cputs("But we escaped from "); print_msg(M_but_we_escaped); - cprintulong(lost); + cprintuint(lost); // cputs(" of 'em!"); print_msg(M_of_em); @@ -1610,16 +1647,16 @@ void port_stats(void) gotoxy(21, 4); in_use = warehouse_in_use(); cblank(5); - cprintulong(in_use); + cprintuint(in_use); gotoxy(21, 6); cblank(5); - cprintulong(10000 - in_use); + cprintuint(10000 - in_use); for(i = 0; i < 4; ++i) { gotoxy(12, i + 3); cblank(5); - cprintulong(hkw_[i]); + cprintuint(hkw_[i]); } /* @@ -1650,7 +1687,7 @@ void port_stats(void) gotoxy(22, 8); cblank(5); - cprintulong(guns); + cprintuint(guns); for(i = 0; i < 4; ++i) { gotoxy(12, i + 9); @@ -1681,7 +1718,7 @@ void port_stats(void) cputs(months + 4 * (month - 1)); // rvs_off(); cspace(); - cprintulong(year); + cprintuint(year); gotoxy(30, 6); cblank(10); @@ -1701,7 +1738,7 @@ void port_stats(void) // if(i < 2) rvs_on(); cputs(st[i]); cputc(':'); - cprintulong(status); + cprintuint(status); // rvs_off(); gotoxy(6, 14); @@ -1747,7 +1784,7 @@ void mchenry(void) { clear_msg_window(); // cputs("Och, 'tis a pity to be "); print_msg(M_tis_a_pity); - cprintulong(percent); + cprintuint(percent); // cputs("% damaged.\r\nWe can fix yer whole ship for "); print_msg(M_percent_damaged); cprintulong(repair_price); @@ -1903,11 +1940,11 @@ void final_stats(void) cprintulong(capacity); // cputs(" units with "); print_msg(M_units_with); - cprintulong(guns); + cprintuint(guns); // cputs(" guns\r\n\n" // "You traded for "); print_msg(M_you_traded_for); - cprintulong(years); + cprintuint(years); // cputs(" year"); print_msg(M_spc_year); if (years != 1) @@ -1916,7 +1953,7 @@ void final_stats(void) } // cputs(" and "); print_msg(M_spc_and_spc); - cprintulong(month); + cprintuchar(month); // cputs(" month"); print_msg(M_spc_month); if (month > 1) @@ -2072,10 +2109,17 @@ char have_no_cargo(void) { return 1; } +#ifdef CART_TARGET +# pragma code-name (push, "HIGHCODE") +#endif void you_have_only(void) { // cputs("You have only "); print_msg(M_you_have_only); } +#ifdef CART_TARGET +# pragma code-name (pop) +#endif + void transfer(void) { @@ -2134,7 +2178,7 @@ void transfer(void) gotoxy(0, 21); // cputs("Your warehouse will only hold an\r\nadditional "); print_msg(M_whouse_only_hold); - cprintulong(10000 - in_use); + cprintuint(10000 - in_use); cprint_taipan_bang(); good_joss_sound(); @@ -2184,7 +2228,7 @@ void transfer(void) // gotoxy(0, 18); // clrtobot(); you_have_only(); - cprintulong(hkw_[i]); + cprintuint(hkw_[i]); cprint_taipan_period(); // cputs("\r\n"); crlf(); @@ -2264,7 +2308,7 @@ void quit(void) { num_ships = 9999; } - cprintulong(num_ships); + cprintuint(num_ships); // cputs(" hostile ship"); print_msg(M_hostile_ship); if(num_ships != 1) cputc_s(); @@ -2320,7 +2364,7 @@ void quit(void) static int num_ships; num_ships = randi()%((capacity / 5) + guns) + 5; - cprintulong(num_ships); + cprintuint(num_ships); /* "ships" will always be plural (at least 5 of them) */ // cputs(" ships of Li Yuen's pirate\r\nfleet"); print_msg(M_ships_of_fleet); @@ -2666,10 +2710,10 @@ void elder_brother_wu(void) "additional "); */ print_msg(M_aware_of_your_plight); - cprintulong(i); + cprintuint(i); // cputs(" if you will pay back\r\n"); print_msg(M_if_you_will_pay_back); - cprintulong(j); + cprintuint(j); // cputs(". Are you willing"); print_msg(M_are_you_willing); cprint_taipan_prompt(); @@ -2779,7 +2823,7 @@ void elder_brother_wu(void) compradores_report(); cprint_bad_joss(); - cprintulong(num); + cprintuint(num); /* cputs(" of your bodyguards have been killed\r\n" "by cutthroats and you have been robbed\r\n" @@ -2931,11 +2975,17 @@ int port_choices(void) { return choice; } +#ifdef CART_TARGET +# pragma code-name (push, "HIGHCODE") +#endif void print_bar_line(void) { cprint_pipe(); cspaces(38); cprint_pipe(); } +#ifdef CART_TARGET +# pragma code-name (pop) +#endif /* TODO: rewrite in asm, or at least better C */ void name_firm(void) { @@ -3146,6 +3196,9 @@ void sell(void) { return; } +#ifdef CART_TARGET +# pragma code-name (push, "HIGHCODE") +#endif char would_overflow(unsigned long a, unsigned long b) { return ((UINT32_MAX - b) <= a); } @@ -3160,6 +3213,10 @@ void too_much_cash(void) { bad_joss_sound(); timed_getch(); } +#ifdef CART_TARGET +# pragma code-name (pop) +#endif + void visit_bank(void) { @@ -3355,7 +3412,7 @@ int main(void) { cprint_elder_brother_wu(); // cputs("has sent "); print_msg(M_has_sent); - cprintulong(braves); + cprintuint(braves); // cputs(" braves\r\nto escort you to the Wu mansion"); print_msg(M_braves_to_escort); cprint_taipan_period(); -- cgit v1.2.3