Jump to content


Free space and code optimisation in "JSW"

261 replies to this topic

#251 Norman Sword

Norman Sword

    Advanced Member

  • Member
  • PipPipPip
  • 196 posts

Posted 21 November 2018 - 12:09 PM

This is a re-use of the same algorithm. This time it translates a key press into a key value. Could be used for high score input which uses the keyboard to type in a name and not the easy scroll letters to get an input. The big wastage is the translate table. The purpose of typing this is only to show a quick re purposing of a routine. (Of note I have seen far worse than this)




IN A,( C )

LD E,5




JR NC,key_pressed


JR NZ,keyloop2


JR NC,keyloop1
JR C,keyloop1   << corrected

JR key_input




LD A,(HL)                 ;the key value from the keyboard



TABLE  db   0,"ZXCVASDFGQWERT1234509876POIUY",13,"IJKL ",1,MNB"
TABLE db    0,"ZXCVASDFGQWERT1234509876POIUY",13,"LKJH ",1,"MNB"  <<hopefully corrected


shift translates as 0, symbol shift as 1, enter as 13


Edited to correct the errors from my quick transcribe. 

Edited by Norman Sword, 21 November 2018 - 01:02 PM.

  • IRF likes this

#252 IRF


    Advanced Member

  • Contributor
  • 4,169 posts

Posted 21 November 2018 - 12:33 PM

"JR NC,keyloop1" should read "JR C,keyloop1"?


This entry: "IJKL ", should be "LKJH ", (with the Space character at the end, before the symbol shift entry)?

#253 Norman Sword

Norman Sword

    Advanced Member

  • Member
  • PipPipPip
  • 196 posts

Posted 21 November 2018 - 12:51 PM

Very surprised it did not contain far more errors. 

I will edit but leave the errors obvious.


  • IRF likes this

#254 IRF


    Advanced Member

  • Contributor
  • 4,169 posts

Posted 19 February 2019 - 07:12 PM

I've found a six nine-byte saving in the 'Initialise the title screen' routine, by replacing the individual checks of various attribute values at #8844-#8870, inserting a couple of look-up tables and using two CPIR commands.


I'll type up a disassembly when I find the time.  :)

Edited by IRF, 20 February 2019 - 06:19 PM.

#255 IRF


    Advanced Member

  • Contributor
  • 4,169 posts

Posted 24 February 2019 - 10:34 AM

There follows a disassembly of my rewrite of the Impossible Triangle-drawing code, as mentioned in my previous post.  The rewritten part of the routine now saves eight bytes, compared with the original.


N.B. I believe that this is exactly the sort of thing that the CPIR command should be used for (unlike Matthew's dodgy application of CPIR in the room-drawing code, which gives rise to the Cell Graphics Bug).



Title_screen_data           EQU    #885D       ; A new data table, which contains all the attribute values which were individually checked

                                                                     ; via CP #nn commands in the original code (and the former operand of a LD A, #nn command)

Triangle_graphic_data    EQU    #8431       ; The original table containing the pixel-graphics used to create the impossible triangle.

                                                                     ; There are two halves to this table (at #8431 and #8441), and each half contains a pair

                                                                     ; of two eight-byte graphics (e.g. graphics start at #8431 and #8439 for the first half of the table)


ORG: #8841

LD DE, #5800



LD A, (DE)

LD HL, Title_screen_data            ; HL now points at the start of the data table, in preparation for the CPIR loops (and other commands) that follow

LD BC, #0005                              ; BC counts down the CPIR loop, but B is also used to indicate which half of the graphic data at #8431 is picked up

CPIR                                            ; Search through the first five entries in the data table 

JR Z, Nothing_to_draw                ; If there is a match, then this particular screen cell contains no pixel-graphics


LD C, #03                                    ; B still holds 00 at this point (and HL is pointing at the next part of the data table)

CPIR                                            ; Search through the next three entries in the data table

JR Z, Draw_triangle_segment     ; If there is a match, then draw a part of the triangle using the first half of the graphic data at #8431


CP (HL)                                       ; Check A against the penultimate value in the data table...

INC HL                                         ; ...and move HL on to the final entry in the table (I tried a CPI command here, but that doesn't preserve B = #00)

JR Z, switch_INK_and_PAPER   ; If there is a match with the penultimate entry, then we are at the 'tricky corner' of the triangle


LD B, #10                                    ; No match in the data table, so we need to select a graphic from the second half of the pixel data

JR Draw_triangle_segment         ' (i.e. the parts of the triangle which slope 'up-to-the-right')

Title_screen_data:                    ; This table could be moved elsewhere in the code, but every path through this routine jumps past it,
                                                  ; so it can safely be left here
DEFB #00 #09 #24 #2D #D3    ; These entries correspond to parts of the screen with no pixel-graphics (i.e. the black background, flashing lettering, 
                                                  ; or solid parts of the triangle which have matching INK and PAPER colours)
DEFB #05 #08 #29            ; All remaining entries in the table correspond to parts of the triangle which slope 'down-to-the-right'
DEFB #2C #25              ; If the attribute in the cell under consideration is #2C (green INK/cyan PAPER), then replace it with #25 (cyan INK/green PAPER)
; N.B. I could have save an extra byte by retaining the original commands for the last two entries [CP #2C and LD A, #25 / LD (DE), A],
; and omitting the last two entries in the table, but I considered it more elegant to have all the data stored within a single data table
DEFS #08                                  ; Eight unused bytes (NOPs) - the point of the exercise!  (These can obviously be consolidated elsewhere)



LD A, (HL)                                    ; Pick up the final entry in the data table and update the attribute in this cell (this swaps the INK/PAPER colours around...

LD (DE), A                                    ; ... which allows the green/cyan corner of the triangle to be drawn using all four of the graphics at #8431)


; N.B. From hereon in, there are further byte-efficiencies to be achieved, which are documented earlier in this thread,

; but which I haven't (yet) incorporated below




AND #01                                      ; Whether E has an even or odd value determines which half of the selected pair of graphics from #8431 is used




OR B                                            ; Determines which pair of graphics from #8431 is used (N.B. this has been changed from the OR C in the original code)


LD B, #00

LD HL, Triangle_graphic_data



BIT 0, D

LD D, #40

JR Z, correct_part_of_screen_identified

LD D, #48


LD B, #08

CALL #969B






CP #5A

JP NZ, Impossible_triangle_loop



EDIT: I should also mention that the above rewrite still works if the erroneous attribute in the original title screen is corrected (i.e. the green/black cell inside the lower part of the letter 'S', which should properly be green and blue).

This can be fixed by editing the data at source, within page #98 (i.e. POKE #98D2, #0C) - no change to the new table at #885D is required, because the corresponding triangle segment slopes down-to-the-left, and so it doesn't need a specific entry in the table (the correct graphic is selected 'by default').

Edited by IRF, 24 February 2019 - 11:08 AM.

#256 Spider


    DEC (HL)

  • Administrator
  • 3,882 posts

Posted 24 February 2019 - 08:07 PM

I did wonder a while back if there was a better way of doing this, not the actual code more the way the 'data' for it is present. I vaguely recall trying a fully compressed full screen to expand and LDIR into screen memory although from what I remember there were no byte savings from this, given it had to live 'somewhere' anyway in its original format.


Impressive stuff. :thumbsup:

Changing order to chaos since 1984

#257 jetsetdanny


    Advanced Member

  • Contributor
  • 2,075 posts

Posted 02 March 2019 - 07:36 PM

Yes, impressive stuff, Ian! - thanks for this :).

#258 Norman Sword

Norman Sword

    Advanced Member

  • Member
  • PipPipPip
  • 196 posts

Posted 04 March 2019 - 12:41 AM

The way the logo is stored is poor design. It is possible (i have done so) to reduce the size of the title screen and its data by around 200+ bytes, it might be nearer 300 bytes.


Edited by Norman Sword, 06 March 2019 - 10:44 AM.

#259 IRF


    Advanced Member

  • Contributor
  • 4,169 posts

Posted 04 March 2019 - 01:42 AM

I'm aware that there are large areas of the title screen with many consecutive identical attribute values (e.g. the first two character rows all hold 00), where it is much more efficient to use a few simple loops to write the appropriate values to the 'uniform' parts of the screen, instead of storing whole chunks of repetitive data (e.g. 64 consecutive 00 bytes for the top two rows) and copying the whole screen using a single LDIR command (as was the case in the original code).


EDIT: That is to say, the amount of bytes saved in optimising the storage of the Title Screen's attribute data, vastly outweighs the modest saving which I have just come up with for the routine that draws the Impossible Triangle's pixels based on the attribute data.

Edited by IRF, 04 March 2019 - 05:45 PM.

#260 IRF


    Advanced Member

  • Contributor
  • 4,169 posts

Posted 11 June 2019 - 12:33 PM

Small rewrite in the JSW game initialisation code which saves a byte:


87F5   LD HL,$857C     87F8   LD (HL),$30     87FA   INC HL     87FB   LD (HL),$30     87FD   INC HL     87FE   LD (HL),$30


LD HL, #857C

LD BC, #0330


LD (HL), C


DJNZ loop

Edited by IRF, 11 June 2019 - 12:34 PM.

1 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

    Bing (1)