User Tools

Site Tools


blog:pushbx:2025:0727_late_july_work

Late July work

2025-07-27

ACEGALS

inicomp

kernwrap

lDOS kernel

LZEXE

The CODEBUF1 mystery

It appears that the size of CODEBUF1 of 128 bytes was chosen without much reason. While it is enough, it was more than the exact buffer size needed. I wrote a long comment on this in the long literal command changeset:

CODEPTR		dw ?
MASQUE		dw ?
CODEBUF		dw ?
CODEBUF1	resb (3 + LONGESTLITERAL) * 8 + 1
	; We do now check for CODEBUF1 overflow in PutCh, but we
	;  don't want that to happen. The following commands store
	;  immediates into the CODEBUF1 here:
	;
	; Single literal: 1 bit tags, 1 byte immediate
	; Short match: 4 bit tags, 1 byte immediate
	; Medium match: 2 bit tags, 2 bytes immediate
	; Long match: 2 bit tags, 3 bytes immediate
	; Segment change: 2 bit tags, 3 bytes immediate (seldom)
	; End of stream: 2 bit tags, 3 bytes immediate (once)
	; Long literal: 2 bit tags, 3 + N bytes immediate
	;
	; So 16 tag bits can at most contain:
	;
	; 16 single literals
	; 4 short matches
	; 8 medium or long commands,
	;  or 7 medium or long commands and 1 single literal

%if 0

Example of overflowing 24 bytes (no -l):

	bytes	bits	index
	2 bits	14	0
putcodebuf	0
3 bytes			0
	2 bits	2	1
3 bytes 6		1
	2 bits	4	2
3 bytes 9		2
	2 bits	6	3
3 bytes 12		3
	2 bits	8	4
3 bytes 15		4
	2 bits	10	5
3 bytes 18		5
	2 bits	12	6
3 bytes 21		6
	2 bits	14	7
3 bytes 24		7
	1 bit	15	8
1 bytes 25		8

%endif
	;
	; Prior to the long literal support, 2 tag bits could at
	;  most encode 3 immediate bytes. The first 3 bytes can be
	;  emitted immediately after flushing the tag word. Thus
	;  we have to account for 8 3-byte commands and then the
	;  possibility of a single literal command which leaves us
	;  with 7 times 2 tag bits (the 0th command already flushed
	;  its tag bits) plus 1 tag bit, fitting in the 16-bit tag
	;  word with the last command emitting its immediate byte
	;  with 15 tag bits stored.
	; This indicates that (8 * 3) + 1 = 25 bytes were needed in
	;  the CODEBUF1. However, 128 bytes were originally used.
	;  This appears to have been an oversight.
	;
	; The long literal command allows to encode 515 bytes for
	;  every 2 tag bits, so the buffer needs to hold eight
	;  times that number plus 1 for the single-literal byte.
	;  This is what is calculated above.
.end:

Basically, the fullest that the immediate buffer (aka CODEBUF1) can get is to first see 8 commands with the maximum amount of immediates. That was 3 bytes prior to the long literals addition. The very first of the 8 commands must be positioned so its two tag bits fill the tag word (CODEBUF) completely and cause a flush, so that the 3 bytes are entered into the immediate buffer with 16 bits still available in the tag buffer. So the 8 long commands will fill 14 of the 16 tag bits.

Then, a single literal command must follow, which will not completely fill the tag buffer but rather leave it at 15 bits filled. This adds a single immediate to the immediate buffer. If a 9th long command follows instead, or a second single literal command, then the tag buffer is exhausted and the entire buffer flushed.

Therefore, the immediate buffer must be of size eight times the immediate length of the longest command, plus 1. This means prior to the long literal command, 25 bytes would have sufficed. With LONGESTLITERAL as 512, the longest command has a literal length of 515 (512 + 3) so the immediate buffer needs to hold 8 * 515 + 1 bytes, or 4096 + 24 + 1, or 4121 bytes.

Initially I was annoyed at the uncommented size of the immediate buffer as a hardcoded 128. Now it seems like that number was just chosen as a "more than enough" solution without regard to the exact needed size. For the long literal command support, however, I wanted to know exactly how much memory would be needed.

I'm considering to assemble lzss.nas thrice, for the TPC and FPC builds of lzexe.pas and another build for lzexedat.asm, which would allow to save some memory not used by the lzexe.pas utility. In this case, a build without the long literal command should allocate 25 bytes to the immediate buffer.

lDebug

At this point in the night (03:14) from Friday to Saturday, I knew that both the help depacker and the ELD depacker were broken, but I called it a day. At 08:25 the following Saturday I continued:

You could leave a comment if you were logged in.
blog/pushbx/2025/0727_late_july_work.txt · Last modified: 2025-07-27 17:24:50 +0200 Jul Sun by ecm