Кто быстрее?



Решая некоторые задачи, я столкнулся с умножением на z80

Решение самое простое:


Multiply:                        ; this routine performs the operation HL=D*E
  ld hl,0                        ; HL is used to accumulate the result
  ld a,d                         ; checking one of the factors; returning if it is zero
  or a
  ret z
  ld b,d                         ; one factor is in B
  ld d,h                         ; clearing D (H is zero), so DE holds the other factor
MulLoop:                         ; adding DE to HL exactly B times
  add hl,de
  djnz MulLoop
  ret


или так

imul   ld e,d              ; HL = H * D
       ld a,h              ; make accumulator first multiplier.
       ld hl,0             ; zeroise total.
       ld d,h              ; zeroise high byte so de=multiplier.
       ld b,8              ; repeat 8 times.
imul1  rra                 ; rotate rightmost bit into carry.
       jr nc,imul2         ; wasn't set.
       add hl,de           ; bit was set, so add de.
       and a               ; reset carry.
imul2  rl e                ; shift de 1 bit left.
       rl d
       djnz imul1          ; repeat 8 times.
       ret


Что мне нравится в процедуре: 1. Нет учета знака множителей 2. Медленно 3. Косяк с определением умножения на 0.

п.2 можно немножко пофиксить, развернув цикл 8 раз(пример 2)
п.1 можно немного исправить, дописав код проверки знака. Я вернулся к старой процедуре, которую писал еще раньше под задачу:


LD A,E
XOR D
AND #80;знак чисел помещается в AF'
EXA

ld a,e
or a
ret z

jp p,no_e
neg
ld e,a
no_e:
ld a,d
or a
ret z

jp p,no_d
neg
ld d,a
no_d:

 xor a
  dup 8
  RR E
  JR NC,$+3
  ADD A,D
  RRA
 edup
        EXA
        JR Z,ALLPL;если в AF' 0, то не нужно менять знак результата
        EXA
        NEG; A=-A
        EXA
ALLPL   EXA
        RET

Однако, у моего способа есть маленький недостаток: при умножении 8бит на 8бит получается не 16 бит а старший байт слова. вызвав MUL2 с DE=$0203 получится А=0. И выходит медленно. Как тут быть?
/*слышны робкие голоса: «можно, ДмитрьВикторович?»*/
Верно, следует вспомнить об одном способе, который почему-то назвали Russian multiplication, он реализован на 6502.

Раз речь пошла о z80, стоило упомянуть о том, как сделано умножение:
для MSX есть статья Multiplication on a Z80
я приведу часть, поскольку сайт иногда падает:


; IN : A and D are to be multiplied
; OUT: HL is result
; CHANGES : AF,BC,E,HL
;
	LD	E,A
	SUB	D
	LD	H,MULTAB/256
	LD	L,A
	LD	C,(HL)
	INC	H
	LD	B,(HL)
	LD	A,E
	ADD	A,D
	LD	L,A
	LD	E,(HL)
	DEC	H
	LD	L,(HL)
	LD	H,E
	OR	A
	SBC	HL,BC

;таблица MULTAB должна быть выровнена по адресу кратному 256
MULTAB	DB	0, 0, 1, 2, 4, 6, 9, 12, 16, 20
	DB	25, 30, 36, 42, 49, 56, 64, 72, 81, 90
	DB	100, 110, 121, 132, 144, 156, 169, 182, 196, 210
	DB	225, 240, 0, 16, 33, 50, 68, 86, 105, 124
	DB	144, 164, 185, 206, 228, 250, 17, 40, 64, 88
	DB	113, 138, 164, 190, 217, 244, 16, 44, 73, 102
	DB	132, 162, 193, 224, 0, 32, 65, 98, 132, 166
	DB	201, 236, 16, 52, 89, 126, 164, 202, 241, 24
	DB	64, 104, 145, 186, 228, 14, 57, 100, 144, 188
	DB	233, 22, 68, 114, 161, 208, 0, 48, 97, 146
	DB	196, 246, 41, 92, 144, 196, 249, 46, 100, 154
	DB	209, 8, 64, 120, 177, 234, 36, 94, 153, 212
	DB	16, 76, 137, 198, 4, 66, 129, 192

	DB	0, 192, 129, 66, 4, 198, 137, 76, 16, 212
	DB	153, 94, 36, 234, 177, 120, 64, 8, 209, 154
	DB	100, 46, 249, 196, 144, 92, 41, 246, 196, 146
	DB	97, 48, 0, 208, 161, 114, 68, 22, 233, 188
	DB	144, 100, 57, 14, 228, 186, 145, 104, 64, 24
	DB	241, 202, 164, 126, 89, 52, 16, 236, 201, 166
	DB	132, 98, 65, 32, 0, 224, 193, 162, 132, 102
	DB	73, 44, 16, 244, 217, 190, 164, 138, 113, 88
	DB	64, 40, 17, 250, 228, 206, 185, 164, 144, 124
	DB	105, 86, 68, 50, 33, 16, 0, 240, 225, 210
	DB	196, 182, 169, 156, 144, 132, 121, 110, 100, 90
	DB	81, 72, 64, 56, 49, 42, 36, 30, 25, 20
	DB	16, 12, 9, 6, 4, 2, 1, 0

	DB	0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	DB	0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	DB	0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	DB	0, 0, 1, 1, 1, 1, 1, 1, 1, 1
	DB	1, 1, 1, 1, 1, 1, 2, 2, 2, 2
	DB	2, 2, 2, 2, 2, 2, 3, 3, 3, 3
	DB	3, 3, 3, 3, 4, 4, 4, 4, 4, 4
	DB	4, 4, 5, 5, 5, 5, 5, 5, 5, 6
	DB	6, 6, 6, 6, 6, 7, 7, 7, 7, 7
	DB	7, 8, 8, 8, 8, 8, 9, 9, 9, 9
	DB	9, 9, 10, 10, 10, 10, 10, 11, 11, 11
	DB	11, 12, 12, 12, 12, 12, 13, 13, 13, 13
	DB	14, 14, 14, 14, 15, 15, 15, 15

	DB	16, 15, 15, 15, 15, 14, 14, 14, 14, 13
	DB	13, 13, 13, 12, 12, 12, 12, 12, 11, 11
	DB	11, 11, 10, 10, 10, 10, 10, 9, 9, 9
	DB	9, 9, 9, 8, 8, 8, 8, 8, 7, 7
	DB	7, 7, 7, 7, 6, 6, 6, 6, 6, 6
	DB	5, 5, 5, 5, 5, 5, 5, 4, 4, 4
	DB	4, 4, 4, 4, 4, 3, 3, 3, 3, 3
	DB	3, 3, 3, 2, 2, 2, 2, 2, 2, 2
	DB	2, 2, 2, 1, 1, 1, 1, 1, 1, 1
	DB	1, 1, 1, 1, 1, 1, 1, 0, 0, 0
	DB	0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	DB	0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	DB	0, 0, 0, 0, 0, 0, 0, 0


Z80 Bits описывает тот же способ — генерация таблицы и умножение. Еще раз оставлю для истории


1.4 Square Table 8-bit * 8-bit Signed

Input: B = Multiplier, C = Multiplicand (both in range -128..127)
Output: HL = Product

Note: Routine uses one of these two formulas: 2ab = (a + b)^2 - a^2 - b^2 or 2ab = a^2 + b^2 - (a - b)^2, depends if (a + b) overflows or not. Powering by 2 is done by table lookup. 512 bytes long table is aligned to 256 byte boundary and contains entries of form SqrTab[x] = x^2. If we treat one of the operands as fractional number -1..1 premultiplied by 128, 2ab performs native shift of the result into register H. That's especially useful e.g. for x * sin(y). Otherwise we have to shift HL right (divide it by 2). We could divide table entries by 2 instead but that causes loss of precision.

Mul8x8	ld	h,SqrTab/256
	ld	l,b
	ld	a,b
	ld	e,(hl)
	inc	h
	ld	d,(hl)		; DE = a^2
	ld	l,c
	ld	b,(hl)
	dec	h
	ld	c,(hl)		; BC = b^2
	add	a,l		; let's try (a + b)
	jp	pe,Plus		; jump if no overflow

	sub	l
	sub	l
	ld	l,a
	ld	a,(hl)
	inc	h
	ld	h,(hl)
	ld	l,a		; HL = (a - b)^2
	ex	de,hl
	add	hl,bc
	sbc	hl,de		; HL = a^2 + b^2 - (a - b)^2

;	sra	h		; uncomment to get real product
;	rr	l
	ret

Plus	ld	l,a
	ld	a,(hl)
	inc	h
	ld	h,(hl)
	ld	l,a		; HL = (a + b)^2
	or	a
	sbc	hl,bc
	or	a
	sbc	hl,de		; HL = (a + b)^2 - a^2 - b^2

;	sra	h		; uncomment to get real product
;	rr	l
	ret
Square table generator is based on observation that differences between consecutive squares (0, 1, 4, 9, 16, 25, ...) form a sequence of odd numbers. (1, 3, 5, 7, 9, ...). Thus, by adding successive odd numbers iteratively we generate integer squares.

	ld	hl,SqrTab	; must be a multiple of 256
	ld	b,l
	ld	c,l		; BC holds odd numbers
	ld	d,l
	ld	e,l		; DE holds squares

SqrGen	ld	(hl),e
	inc	h
	ld	(hl),d		; store x^2
	ld	a,l
	neg
	ld	l,a
	ld	(hl),d
	dec	h
	ld	(hl),e		; store -x^2
	ex	de,hl
	inc	c
	add	hl,bc		; add next odd number
	inc	c
	ex	de,hl

	cpl			; one byte replacement for NEG, DEC A
	ld	l,a
	rla
	jr	c,SqrGen
1.5 Square Table Driven 6-bit * 6-bit Signed

The first thing that should be pointed out here is that the topic is not particularly correct. Actually, the routine is able to multiply any pair of numbers x, y as long as (x + y) <= 127 and (x - y) >= -128. But if x, y are signed 6-bit values these rules are never violated, no overflows occur and no specific checking is needed.

The routine is based on a formula 4xy = (x + y)^2 - (x - y)^2 and uses the same lookup table (see previous chapter) except all table entries are pre-divided by 4 to avoid division (shifting) at the end. An explanation why it works can be found here. In case we leave the table as is, routine nicely handles fixed point multiplications. That means, if we treat one of the operands as fractional number in range (-1, 1) pre-multiplied by 64, integer part of the result gets shifted handily into register H.

Note: SqrTab must be aligned to 256 byte boundary.

Input: B = Multiplier, C = Multiplicand
Output: BC = Product

Mul6x6	ld	h,SqrTab/256
	ld	d,h
	ld	a,b
	add	a,c		; A = x + y
	ld	l,a
	ld	a,b
	sub	c		; A = x - y
	ld	e,a
	ld	a,(de)		; subtract lower byte
	sub	(hl)		; lower byte of (x + y)^2 - (x - y)^2
	ld	c,a
	inc	h
	inc	d
	ld	a,(de)
	sbc	a,(hl)		; higher byte of (x + y)^2 - (x - y)^2
	ld	b,a
This is the fastest version I could come up with but there's also slightly slower one which preserves one register pair:

Input: B = Multiplier, C = Multiplicand
Output: HL = Product

Mul6x6	ld	h,SqrTab/256
	ld	a,b
	sub	c		; A = x - y
	ld	l,a
	ld	a,b
	add	a,c		; A = x + y
	ld	c,(hl)
	inc	h
	ld	b,(hl)		; BC = (x - y)^2
	ld	l,a
	ld	a,(hl)
	dec	h
	ld	l,(hl)
	ld	h,a		; HL = (x + y)^2
	or	a
	sbc	hl,bc		; HL = (x + y)^2 - (x - y)^2
It's also possible to speed up this routine by having two consecutive look-up tables where first table is negated. Question is, however, if 4 cycles are worth wasting another 512 bytes.

Mul6x6	ld	h,SqrTab/256
	ld	a,b
	sub	c		; A = x - y
	ld	l,a
	ld	a,b
	add	a,c		; A = x + y
	ld	c,(hl)
	inc	h
	ld	b,(hl)		; BC = -(x - y)^2, that's the trick
	inc	h
	ld	l,a
	ld	a,(hl)
	inc	h
	ld	h,(hl)
	ld	l,a		; HL = (x + y)^2
	add	hl,bc		; HL = (x + y)^2 - (x - y)^2


Чем мне понравилась последняя версия, это тем, что при умножении используются только BC и HL.

Но и это еше не все! Осталась процедура, написанная на Amstrad CPC:
Ultrafast Multiplication

;The following is the fastest possible multiplication routine (in a little specialised way) for the CPC, coded by Prodatron for the
;Voyage 1993 Megademo and the Digital Orgasm demo. It works with signed values and is mainly used for 3D graphic calculations. You can
;change it to HL=DE*L by removing LD A,H in front of every RET command inside the MULxxx sub-routines, but in this case L has to be
;positive.

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;@                                                                            @
;@              U L T R A F A S T   M U L T I P L I C A T I O N               @
;@                                                                            @
;@                   (c)oded 1993 by Prodatron / SymbiosiS                    @
;@                                                                            @
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

;### MULTI -> Multiplies two signed integer values (A=DE*L/256)
;### Input      DE=value1 (signed), L=value2 (signed)
;### Output     A=DE*L/256 (signed)
;### Destroyed  F,BC,DE,HL
MULTI   LD   H,MULTAB/512
        ADD  HL,HL
        LD   C,(HL)
        INC  HL
        LD   B,(HL)
        EX   DE,HL
        PUSH BC
        RET
;

DS -$ MOD 512

MULTAB
DEFW MUL000,MUL001,MUL002,MUL003,MUL004,MUL005,MUL006,MUL007,MUL008,MUL009,MUL010,MUL011,MUL012,MUL013,MUL014,MUL015,MUL016,MUL017,MUL018,MUL019,MUL020,MUL021,MUL022,MUL023,MUL024,MUL025,MUL026,MUL027,MUL028,MUL029,MUL030,MUL031,MUL032,MUL033
DEFW MUL034,MUL035,MUL036,MUL037,MUL038,MUL039,MUL040,MUL041,MUL042,MUL043,MUL044,MUL045,MUL046,MUL047,MUL048,MUL049,MUL050,MUL051,MUL052,MUL053,MUL054,MUL055,MUL056,MUL057,MUL058,MUL059,MUL060,MUL061,MUL062,MUL063,MUL064,MUL065,MUL066,MUL067
DEFW MUL068,MUL069,MUL070,MUL071,MUL072,MUL073,MUL074,MUL075,MUL076,MUL077,MUL078,MUL079,MUL080,MUL081,MUL082,MUL083,MUL084,MUL085,MUL086,MUL087,MUL088,MUL089,MUL090,MUL091,MUL092,MUL093,MUL094,MUL095,MUL096,MUL097,MUL098,MUL099,MUL100,MUL101
DEFW MUL102,MUL103,MUL104,MUL105,MUL106,MUL107,MUL108,MUL109,MUL110,MUL111,MUL112,MUL113,MUL114,MUL115,MUL116,MUL117,MUL118,MUL119,MUL120,MUL121,MUL122,MUL123,MUL124,MUL125,MUL126,MUL127
DEFW NEG128,NEG127,NEG126,NEG125,NEG124,NEG123,NEG122,NEG121,NEG120,NEG119,NEG118,NEG117,NEG116,NEG115,NEG114,NEG113,NEG112,NEG111,NEG110,NEG109,NEG108,NEG107,NEG106,NEG105,NEG104,NEG103,NEG102,NEG101,NEG100,NEG099,NEG098,NEG097,NEG096,NEG095
DEFW NEG094,NEG093,NEG092,NEG091,NEG090,NEG089,NEG088,NEG087,NEG086,NEG085,NEG084,NEG083,NEG082,NEG081,NEG080,NEG079,NEG078,NEG077,NEG076,NEG075,NEG074,NEG073,NEG072,NEG071,NEG070,NEG069,NEG068,NEG067,NEG066,NEG065,NEG064,NEG063,NEG062,NEG061
DEFW NEG060,NEG059,NEG058,NEG057,NEG056,NEG055,NEG054,NEG053,NEG052,NEG051,NEG050,NEG049,NEG048,NEG047,NEG046,NEG045,NEG044,NEG043,NEG042,NEG041,NEG040,NEG039,NEG038,NEG037,NEG036,NEG035,NEG034,NEG033,NEG032,NEG031,NEG030,NEG029,NEG028,NEG027
DEFW NEG026,NEG025,NEG024,NEG023,NEG022,NEG021,NEG020,NEG019,NEG018,NEG017,NEG016,NEG015,NEG014,NEG013,NEG012,NEG011,NEG010,NEG009,NEG008,NEG007,NEG006,NEG005,NEG004,NEG003,NEG002,NEG001
;
MUL000 LD HL,0:LD A,H:RET
MUL064 ADD HL,HL
MUL032 ADD HL,HL
MUL016 ADD HL,HL
MUL008 ADD HL,HL
MUL004 ADD HL,HL
MUL002 ADD HL,HL
MUL001 LD A,H:RET
MUL096 ADD HL,HL
MUL048 ADD HL,HL
MUL024 ADD HL,HL
MUL012 ADD HL,HL
MUL006 ADD HL,HL
MUL003 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:LD A,H:RET
MUL080 ADD HL,HL
MUL040 ADD HL,HL
MUL020 ADD HL,HL
MUL010 ADD HL,HL
MUL005 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:RET
MUL112 ADD HL,HL
MUL056 ADD HL,HL
MUL028 ADD HL,HL
MUL014 ADD HL,HL
MUL007 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:RET
MUL072 ADD HL,HL
MUL036 ADD HL,HL
MUL018 ADD HL,HL
MUL009 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:RET
MUL088 ADD HL,HL
MUL044 ADD HL,HL
MUL022 ADD HL,HL
MUL011 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:RET
MUL104 ADD HL,HL
MUL052 ADD HL,HL
MUL026 ADD HL,HL
MUL013 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:RET
MUL120 ADD HL,HL
MUL060 ADD HL,HL
MUL030 ADD HL,HL
MUL015 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:RET
MUL068 ADD HL,HL
MUL034 ADD HL,HL
MUL017 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:RET
MUL076 ADD HL,HL
MUL038 ADD HL,HL
MUL019 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL084 ADD HL,HL
MUL042 ADD HL,HL
MUL021 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:RET
MUL092 ADD HL,HL
MUL046 ADD HL,HL
MUL023 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:RET
MUL100 ADD HL,HL
MUL050 ADD HL,HL
MUL025 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:RET
MUL108 ADD HL,HL
MUL054 ADD HL,HL
MUL027 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:RET
MUL116 ADD HL,HL
MUL058 ADD HL,HL
MUL029 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:ADD HL,BC:LD A,H:RET
MUL124 ADD HL,HL
MUL062 ADD HL,HL
MUL031 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:RET
MUL066 ADD HL,HL
MUL033 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:RET
MUL070 ADD HL,HL
MUL035 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:RET
MUL074 ADD HL,HL
MUL037 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:RET
MUL078 ADD HL,HL
MUL039 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:OR A:SBC HL,BC:LD A,H:RET
MUL082 ADD HL,HL
MUL041 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:RET
MUL086 ADD HL,HL
MUL043 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL090 ADD HL,HL
MUL045 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:RET
MUL094 ADD HL,HL
MUL047 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:RET
MUL098 ADD HL,HL
MUL049 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:RET
MUL102 ADD HL,HL
MUL051 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:RET
MUL106 ADD HL,HL
MUL053 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,BC:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:RET
MUL110 ADD HL,HL
MUL055 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL114 ADD HL,HL
MUL057 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL118 ADD HL,HL
MUL059 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL122 ADD HL,HL
MUL061 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL126 ADD HL,HL
MUL063 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:RET
MUL065 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:RET
MUL067 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:RET
MUL069 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:RET
MUL071 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:OR A:SBC HL,BC:LD A,H:RET
MUL073 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:RET
MUL075 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:RET
MUL077 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,BC:LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:RET
MUL079 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:OR A:SBC HL,BC:LD A,H:RET
MUL081 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:RET
MUL083 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:RET
MUL085 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:RET
MUL087 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:RET
MUL089 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:RET
MUL091 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:RET
MUL093 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:RET
MUL095 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:OR A:SBC HL,BC:LD A,H:RET
MUL097 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:RET
MUL099 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:RET
MUL101 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:RET
MUL103 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:RET
MUL105 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:RET
MUL107 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL109 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:RET
MUL111 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:RET
MUL113 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:RET
MUL115 LD E,L:LD D,H:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,DE:OR A:SBC HL,BC:LD A,H:RET
MUL117 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:RET
MUL119 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL121 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL123 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL125 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:RET
MUL127 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:RET
;
NEG064 ADD HL,HL
NEG032 ADD HL,HL
NEG016 ADD HL,HL
NEG008 ADD HL,HL
NEG004 ADD HL,HL
NEG002 ADD HL,HL
NEG001 LD A,H:NEG:RET
NEG096 ADD HL,HL
NEG048 ADD HL,HL
NEG024 ADD HL,HL
NEG012 ADD HL,HL
NEG006 ADD HL,HL
NEG003 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:LD A,H:NEG:RET
NEG080 ADD HL,HL
NEG040 ADD HL,HL
NEG020 ADD HL,HL
NEG010 ADD HL,HL
NEG005 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:NEG:RET
NEG112 ADD HL,HL
NEG056 ADD HL,HL
NEG028 ADD HL,HL
NEG014 ADD HL,HL
NEG007 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG072 ADD HL,HL
NEG036 ADD HL,HL
NEG018 ADD HL,HL
NEG009 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:NEG:RET
NEG088 ADD HL,HL
NEG044 ADD HL,HL
NEG022 ADD HL,HL
NEG011 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:NEG:RET
NEG104 ADD HL,HL
NEG052 ADD HL,HL
NEG026 ADD HL,HL
NEG013 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:NEG:RET
NEG120 ADD HL,HL
NEG060 ADD HL,HL
NEG030 ADD HL,HL
NEG015 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG068 ADD HL,HL
NEG034 ADD HL,HL
NEG017 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:NEG:RET
NEG076 ADD HL,HL
NEG038 ADD HL,HL
NEG019 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG084 ADD HL,HL
NEG042 ADD HL,HL
NEG021 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:NEG:RET
NEG092 ADD HL,HL
NEG046 ADD HL,HL
NEG023 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG100 ADD HL,HL
NEG050 ADD HL,HL
NEG025 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:NEG:RET
NEG108 ADD HL,HL
NEG054 ADD HL,HL
NEG027 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:NEG:RET
NEG116 ADD HL,HL
NEG058 ADD HL,HL
NEG029 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:ADD HL,BC:LD A,H:NEG:RET
NEG124 ADD HL,HL
NEG062 ADD HL,HL
NEG031 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG066 ADD HL,HL
NEG033 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:NEG:RET
NEG070 ADD HL,HL
NEG035 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:NEG:RET
NEG074 ADD HL,HL
NEG037 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:NEG:RET
NEG078 ADD HL,HL
NEG039 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG082 ADD HL,HL
NEG041 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:NEG:RET
NEG086 ADD HL,HL
NEG043 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG090 ADD HL,HL
NEG045 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG094 ADD HL,HL
NEG047 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG098 ADD HL,HL
NEG049 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:NEG:RET
NEG102 ADD HL,HL
NEG051 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:NEG:RET
NEG106 ADD HL,HL
NEG053 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,BC:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:NEG:RET
NEG110 ADD HL,HL
NEG055 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG114 ADD HL,HL
NEG057 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG118 ADD HL,HL
NEG059 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG122 ADD HL,HL
NEG061 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG126 ADD HL,HL
NEG063 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG065 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:NEG:RET
NEG067 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:NEG:RET
NEG069 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:NEG:RET
NEG071 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG073 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:NEG:RET
NEG075 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:NEG:RET
NEG077 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,BC:LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:NEG:RET
NEG079 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG081 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:NEG:RET
NEG083 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG085 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:NEG:RET
NEG087 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG089 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:NEG:RET
NEG091 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG093 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:NEG:RET
NEG095 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG097 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,BC:LD A,H:NEG:RET
NEG099 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG101 LD C,L:LD B,H:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD A,H:NEG:RET
NEG103 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG105 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:NEG:RET
NEG107 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG109 LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:ADD HL,DE:LD A,H:NEG:RET
NEG111 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG113 LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:NEG:RET
NEG115 LD E,L:LD D,H:ADD HL,HL:LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,DE:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG117 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:LD E,L:LD D,H:ADD HL,HL:ADD HL,DE:ADD HL,HL:ADD HL,HL:ADD HL,DE:LD A,H:NEG:RET
NEG119 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG121 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG123 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG125 LD C,L:LD B,H:ADD HL,HL:LD E,L:LD D,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:OR A:SBC HL,DE:LD A,H:NEG:RET
NEG127 LD C,L:LD B,H:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:ADD HL,HL:OR A:SBC HL,BC:LD A,H:NEG:RET
NEG128 LD A,L:RR H:RRA:NEG:RET


Справочник опкодов z80 есть рядом, считайте, что быстрее?
или кто-то вспомнит или найдет еще один метод?

36 комментариев

avatar
За решение как в самом первом примере я бы убивал. Примеры с умножением посредством таблицы квадратов интересные, но их нужно аккуратно проверять, дают ли они точный ответ или приблизительный (особенно с учётом того что там возвращается 16-битный результат).

Последняя процедура прикольная, у меня экстремальный проигрыватель PSG сделан из похожей лапши.
avatar
Да, забыл ещё одну вещь. В случае с 3D чаще всего умножение с 8-битным результатом, как у тебя, бывает нужно для умножения на синусы и косинусы. У меня в старом буте «Morphine» было сделано более быстрое умножение чем в твоих примерах с помощью таблицы на 16К (8 бит — координата, 6 бит — четверть периода угла, из которой восстанавливается и знак и синус и косинус).
avatar
почему?
avatar
Посчитай такты и узнаешь ответ.
avatar
Мне показалось из-за способа. Но в демах, как ни крути ты такой способ заюзаешь.
avatar
Ты хотел сказать не заюзаю?
avatar
Тебе виднее.
avatar
Тебе виднее, я юзал, но с учетом знакового умножения.
avatar
Теперь по тактам. Ты не написал чётко, там у Baze не одна, а две процедуры.
Первая процедура Baze нацелена на умножение 8-битных чисел. Она даёт результат умножения за 133 такта (плюс 10 тактов на возврат).
Вторая процедура Baze нацелена на умножение 6-битных чисел; она даёт результат за 79 тактов (плюс 10 тактов на возврат).

Рассчитывать среднее время выполнения «ультрабыстрого» умножения с цпц мне сейчас лень. Но можно оценить разброс. Самая быстрая ветка — MUL001, в её случае умножение выполнится за 77 тактов. Одна из самых медленных (я взял тупо самую длинную строчку) — NEG115, в её случае умножение выполнится за 227 тактов. Выглядит так, что 6-битная процедура Baze точно шустрее метода цпц, а «медленная 8-битная» — выполнится за сопоставимое время. По расходу памяти процедура Baze тоже выглядит вполне сопоставимой. Моя оценка — метод Baze можно/нужно попробовать ещё пооптимизировать и тогда возиться с методом с CPC совсем не останется смысла.
avatar
если ты хочешь считать такты CPC, то учти, что у z80 такты другие
avatar
У Z80 такты везде одни и те же. Если у CPC тормоза, то эти тормоза более-менее равномерно скажутся на каждой из этих программ. Поэтому выводы сверху будут верны для любой платформы.

Ещё дополнение: первая процедура Baze — выдаёт точный ответ, все 16 бит. Её можно ускорить, если устроил бы и менее точный ответ (например, только старший байт ответа).
avatar
Неверно.

Насчет Baze: Да, действительно есть две процедуры, я упомянул, что использование HL и BC было удобным.
avatar
Читал, но исходники не изучал, поэтому может быть неактуальным

Приведу часть своей неопубликованной статьи для Demo or Die 2000 года

Табличное умножение 8*8 с учетом знака.
— Умножение производится на основе одной из формул сокращенного умножения, в частности:

(a-b)(a+b)=a^2-b^2

Пусть: ┌──
│ X=a-b
│ Y=a+b
└──

Решая эту систему уравнений получим:

a=(X+Y)/2
b=(Y-X)/2

Тогда произведение X и Y будет определяться из выражения:

X*Y=a^2-b^2=((X+Y)^2 — (Y-X)^2) / 4

Это может выглядеть например так:


 IMUL_HL=D*E
;----------------------------------
;  IN: H=TB_XX/256
;      D=X[-128,127]
;      E=Y[-128,127]
;      BC-NoT USED
;  OUT:HL=D*E
;      A=0 !
;----------------------------------
imul
;----------------------------------
   ld h,tb_xx[
;----------------------------------
   ld a,e
   sub d               ; y-x
   ld l,a
   ld a,e              ; y
   add a,d             ; x+y
   ld e,(hl)
   inc h
   ld d,(hl)           ; (y-x)^2
   ld l,a
   ld a,(hl)
   dec h
   ld l,(hl)
   ld h,a              ; (x+y)^2
   xor a ;... может кому пригодится? :)
   sbc hl,de
;----------------------------------
   ret

min/max=83 tps (без учета RET)

Структура таблицы TB_XX (таблица квадратов чисел от -128 до 127) аналогична структуре таблицы описанной в Spectrum Expert#1 — имеет рaзмер 256*16 бит, с учетом знaкa числa. Единственное отличие, в таблице хранятся квадраты чисел/4
Тaблицa оргaнизовaнa следующим образом: млaдшие бaйты лежaт в первом сегменте, a стaршие в следующем (т.е. по смещению 256)

Процедура генерации несколько отличается от приведенной в SE#1.(Процедура крайне не оптимизирована, но все же более компактна и быстродейственна)


;gen_table x*x   x=(-128;127)
;--------------------------------
gen_xx  ld hl,tb_xx
        ld d,l,e,l
        ld bc,de
lp1     ld (hl),e
        inc h
        ld (hl),d
        dec h
        ex de,hl
        inc bc
        add hl,bc
        inc bc
        ex de,hl
        inc l
        jp p,lp1
        ld de,hl
lp2     ld a,(hl)
        ld (de),a
        inc d,h
        ld a,(hl)
        ld (de),a
        dec d,h
        inc e
        dec l
        jr nz,lp2
        ret
----------------------------

37b
avatar
Осталось построить таблицу
avatar
Там же есть генератор в тексте gen_table x*x
avatar
у Mathrix/Baze другая. Надо будет сравнить.
avatar
rajdee, а ты уверен что у тебя верно учтены знаки при умножении? Вообще, твоя процедура эквивалентна (может, не в деталях) второй процедуре Baze. Но Baze ограничил числа 6 битами, чтобы обойти переполнение, а ты переполнение игнорируешь.

Пытаюсь сейчас сообразить, что произойдёт при переполнениях :)
avatar
Мы все умрем?
avatar
Вспомнил. Дениска на гф спрашивал об умножении:

Mul8x8	ld	h,SqrTab/256
	ld	l,b
	ld	a,b
	ld	e,(hl)
	inc	h
	ld	d,(hl)		; DE = a^2
	ld	l,c
	ld	b,(hl)
	dec	h
	ld	c,(hl)		; BC = b^2
	add	a,l		; let's try (a + b)
;;	jp	pe,Plus		; jump if no overflow
	jp	p,Plus		; jump if no overflow
avatar
Дима, ты хотя бы заглядывай в исходники, которые нам тут выкладываешь. Это кусок первой процедуры Baze.
avatar
казалось бы, причем тут 6бит?
avatar
Не уверен, 17 лет уже прошло, надо будет тесты написать )
avatar
В случае -128*(-128) имеем E-D=0 и E+D=0. Разница квадратов нулей даст тебе опять 0. Твой метод, так же как и второй метод Baze, сработает только если ты сможешь гарантировать отсутствие переполнений, т.е. для x=(-64,63) — те же самые 6 бит.
avatar
Быстрее всего умножают на комке: codebase64.org/doku.php?id=base:6502_6510_maths

Инфа 100%.
avatar
-Товариш, у Вас к заднице газета прилипла!
— Правда?
— Нет, «Известия»!
avatar
Ещё один тип быстрого умножения, который не попал в заметку: zxpress.ru/article.php?id=3606
avatar
только он таблицу не использовал.
avatar
Разумеется, использовал! Только совершенно другую.

Ты скажи, может мне не нужно кидать так инфу? Потому что ты, например, явно в неё не заглядываешь даже.
avatar
точно, я сразу не посмотрел. Инфа о том, кто комодурь считает быстрее — не нужна. Неправда это имхо.
avatar
Это реально правда. По моей ссылке есть 2 точных алгоритма. Первый — быстрее точного алгоритма Baze на 20%. Во втором я не разбирался, но они пишут что он ещё на 30-40% быстрее первого.
avatar
Интересно было бы сравнить с тем способом 6502, что я привел, затем посчитать.
Ты как всегда принимаешь слова на веру.
avatar
Вообще-то, нет, я не принимаю на веру, я посчитал такты.
avatar
Забыл сказать — то что названо у тебя «русским» умножением — неэффективно, так умножать не нужно.
avatar
т.е. не читал? ниже был приведен способ умножения на таблице квадратов. Разве это не тоже самое, что на С64?

Теперь еще пара ремарок.

1. Способ Base/3SC неудобен тем, что 512 байт таблицы никуда не впихнешь — т.е. 1К и ниже идут лесом. Между делом, Baze в Mathrix использовал умножение на основе таблиц квадратов.

2. Никто не вспомнил тот способ, о котором я упомянул в конце топика. В Insult MD строится таблица N*sin(A), это не универсальный способ, но для эффекта он все же побыстрее(такие же способы используются в других демо). Похожее я использовал в Disney MegaDemo, было удобнее хранить не таблицу синусов, а таблицу EL1*sin(N) — отсюда вышли такие 3d фигуры. Вся процедура умножения упирается в выбор значения и учет знака результата. Быстрее или нет — не знаю.
avatar
Дима, но Baze описывает очень эффективный способ генерации этой таблицы. Просмотрел опять?

В Morphine использовалась таблица типа описанной тобой. Хранилось 1/4 периода синуса и множитель синуса мог быть любым 8-битным.
avatar
Не врубился, наверное.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.