OpenCores
no use no use 1/1 no use no use
wb_z80 bug; Next instruction ignored after "ret z" when ~z?
by Unknown on Jun 3, 2007
Not available!
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, I've been experimenting with the wb_z80 core from opencores.org, and I believe I've found a bug. When I simulate the code below, the "push hl" command appears to be completely ignored. I've reproduced this using "ModelSimXE III 6.1e" together with "Xilinx ISE 8.2 webpack". Also, there's definitely a problem with the code (I assume the same thing) when synthesized for a Spartan 3E device. I think what's happening is this: Part of the code that calculates mem_exec_dec is: {I1DCNT {RETsC == ir1 & cf }} & I1_RET |// RET C ; D8 {I1DCNT {RETsM == ir1 & sf }} & I1_RET |// RET M ; F8 {I1DCNT {RETsNC== ir1 & ~cf }} & I1_RET |// RET NC ; D0 {I1DCNT {RETsP == ir1 & ~sf }} & I1_RET |// RET P ; F0 {I1DCNT {RETsPE== ir1 & pvf }} & I1_RET |// RET PE ; E8 {I1DCNT {RETsPO== ir1 & ~pvf}} & I1_RET |// RET PO ; E0 {I1DCNT {RETsNZ== ir1 & ~zf }} & I1_RET |// RET NZ ; C0 {I1DCNT {RETsZ == ir1 & zf }} & I1_RET |// RET Z ; C8 If the "ret z" is taken, then the next state is correctly defined as I1_RET. However, if the z flag is clear, then there's no matching entry in the decoding, which evaluates to value 0, which is the I1_CB state, which simply eats the next instruction byte, I think... Note that other conditional instructions (e.g. jp z, call z) aren't decoded in this way, because they always jump to a single state in order to read the 2-byte address to jump to, and that state then somehow implements the conditional jump, although I haven't managed to trace exactly how yet. I guess the solution is to expand the above decoding, by adding an extra entry for each conditional ret instruction when the condition is false. However, there's no I1_NOP state to use here. I see that the real nop instruction uses the I1_R2R state, so I assume I could do that, although I'd worry about how to ensure that state doesn't actually write to any registers! Does this analysis seem correct? Is I1_R2R the correct next state? code org #0000 reset: set_sp: ld sp, stack_top bug_start: ; Initialize flags, so they're not X ; Probably isn't relevant, but is distracting in wave view ld de, #0000 push de pop af ; Random setup to ensure registers are initialized ld hl, 0xaa55 ld a, 7 ; Start code that exactly matches that where the bug was found cp 0 ret z ; Without this NOP ; nop ; This PUSH is ignored push hl call ret_test pop hl end_bug: jp end_bug ret_test: ret stack_top: equ #07ff -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.2 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGYgZVhk3bo0lNTrURAo/OAJ9WtQ7vsSpJFTxlZU50JOU6k9VyCACePURU xI1Ru7f6W2B6C3jh6jQ/d7A= =dIr6 -----END PGP SIGNATURE-----
wb_z80 bug; Next instruction ignored after "ret z" when ~z?
by Unknown on Jun 5, 2007
Not available!
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Well, the workaround I mentioned below (adding extra decoding entries,
which jump to I1_R2R) seems to work for me. LCD and UART IO are now
working on my board:-)

Stephen Warren wrote:
Hi,

I've been experimenting with the wb_z80 core from opencores.org, and I
believe I've found a bug.

When I simulate the code below, the "push hl" command appears to be
completely ignored. I've reproduced this using "ModelSimXE III 6.1e"
together with "Xilinx ISE 8.2 webpack". Also, there's definitely a
problem with the code (I assume the same thing) when synthesized for a
Spartan 3E device.

I think what's happening is this:

Part of the code that calculates mem_exec_dec is:

{I1DCNT {RETsC == ir1 & cf }} & I1_RET |// RET C ; D8
{I1DCNT {RETsM == ir1 & sf }} & I1_RET |// RET M ; F8
{I1DCNT {RETsNC== ir1 & ~cf }} & I1_RET |// RET NC ; D0
{I1DCNT {RETsP == ir1 & ~sf }} & I1_RET |// RET P ; F0
{I1DCNT {RETsPE== ir1 & pvf }} & I1_RET |// RET PE ; E8
{I1DCNT {RETsPO== ir1 & ~pvf}} & I1_RET |// RET PO ; E0
{I1DCNT {RETsNZ== ir1 & ~zf }} & I1_RET |// RET NZ ; C0
{I1DCNT {RETsZ == ir1 & zf }} & I1_RET |// RET Z ; C8

If the "ret z" is taken, then the next state is correctly defined as
I1_RET. However, if the z flag is clear, then there's no matching entry
in the decoding, which evaluates to value 0, which is the I1_CB state,
which simply eats the next instruction byte, I think...

Note that other conditional instructions (e.g. jp z, call z) aren't
decoded in this way, because they always jump to a single state in order
to read the 2-byte address to jump to, and that state then somehow
implements the conditional jump, although I haven't managed to trace
exactly how yet.

I guess the solution is to expand the above decoding, by adding an extra
entry for each conditional ret instruction when the condition is false.
However, there's no I1_NOP state to use here. I see that the real nop
instruction uses the I1_R2R state, so I assume I could do that, although
I'd worry about how to ensure that state doesn't actually write to any
registers!

Does this analysis seem correct? Is I1_R2R the correct next state?

code
org #0000

reset:
set_sp:
ld sp, stack_top

bug_start:
; Initialize flags, so they're not X
; Probably isn't relevant, but is distracting in wave view
ld de, #0000
push de
pop af
; Random setup to ensure registers are initialized
ld hl, 0xaa55
ld a, 7
; Start code that exactly matches that where the bug was found
cp 0
ret z
; Without this NOP
; nop
; This PUSH is ignored
push hl
call ret_test
pop hl
end_bug:
jp end_bug

ret_test:
ret

stack_top: equ #07ff
_______________________________________________ http://www.opencores.org/mailman/listinfo/cores -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.2 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGZP7rhk3bo0lNTrURAkEDAKD5Hjx3ZRpV+KFCAzLXQlFaPTKNbgCdGvNk Dm9ra32ZbQPcJWWwsYpi618= =WbBK -----END PGP SIGNATURE-----
no use no use 1/1 no use no use
© copyright 1999-2026 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.