Hi, I want to rewrite Z80 port using CGEN. And I have following questions: The Z80 CPU uses prefix opcodes to change opcode tables and operation registers. For example, <0x21 0x34 0x12> is "LD HL,0x1234", but <0xdd 0x21 0x34 0x12> is "LD IX,0x1234". Do I need write both instructions or is it possible to write rule which selects proper instruction set or extract correct register index? Z80 has special rule to form indirect memory operations using index registers. There immediate offset is always third byte of instruction. For example: <0xdd 0x34 0x12> is "INC (IX+0x12)", <0xfd 0x36 0xfe 0xab> is "LD (IY-0x02),0xAB"... But there are "strange" instructions, where index is placed before opcode itself: <0xdd 0xcb 0x10 0x1e> is "RR (IX+0x10)" (<0xcb 0x1e> is "RR (HL)", <0xcb> is opcode prefix, which select another opcode table) and undocumented one <0xdd 0xcb 0x10 0x1f> "RR (IX+0x10),A". Should I write 2 instructions types? eZ80 uses four opcode prefixes (.SIS, .SIL, .LIS, .LIL) which set operation mode (.IL - long instruction (24 bit immediate), .IS - short instruction (16 bit immediate), .S - 16 bit processing, .L - 24 bit processing): <0x40 0x21 0x34 0x12> is "LD.SIS HL,0x1234" and <0x5b 0x21 0x56 0x34 0x12> is "LD.LIL HL,0x123456". These prefixes can be applied to all instructions (but it has no sense for part of instructions). Moreover, assembler should support short mode of instructions (.S, .L, .IS, .IL), which is completed by assembler depending on compiling mode (ADL or Z80). Should I generate all possible combinations (9 x instruction_set)? Is there more correct solution? Best regards, Sergey Belyashov
Hi - > The Z80 CPU uses prefix opcodes to change opcode tables and operation > registers. For example, <0x21 0x34 0x12> is "LD HL,0x1234", but <0xdd 0x21 > 0x34 0x12> is "LD IX,0x1234". Do I need write both instructions or is it > possible to write rule which selects proper instruction set or extract > correct register index? Consider writing prefix opcodes as a normal part of the instruction (so include them in the base-insn-bitsize). So you'd need two separate instructions, one with and one without. You may be able to use cgen macros to generate both flavours from one piece of declaration. > Z80 has special rule to form indirect memory operations using index > registers. There immediate offset is always third byte of instruction. For > example: <0xdd 0x34 0x12> is "INC (IX+0x12)", <0xfd 0x36 0xfe 0xab> is "LD > (IY-0x02),0xAB"... But there are "strange" instructions, where index is > placed before opcode itself: <0xdd 0xcb 0x10 0x1e> is "RR (IX+0x10)" (<0xcb > 0x1e> is "RR (HL)", <0xcb> is opcode prefix, which select another opcode > table) and undocumented one <0xdd 0xcb 0x10 0x1f> "RR (IX+0x10),A". Should > I write 2 instructions types? Probably, if the same operands are not in the same place. > eZ80 uses four opcode prefixes (.SIS, .SIL, .LIS, .LIL) which set operation > mode (.IL - long instruction (24 bit immediate), .IS - short instruction > (16 bit immediate), .S - 16 bit processing, .L - 24 bit processing): <0x40 > 0x21 0x34 0x12> is "LD.SIS HL,0x1234" and <0x5b 0x21 0x56 0x34 0x12> is > "LD.LIL HL,0x123456". These prefixes can be applied to all instructions > (but it has no sense for part of instructions). Moreover, assembler should > support short mode of instructions (.S, .L, .IS, .IL), which is completed > by assembler depending on compiling mode (ADL or Z80). Should I generate > all possible combinations (9 x instruction_set)? Is there more correct > solution? You may be able to represent tehse opcode prefix bytes as an operand, and have a special asm parser/printer that sets them from the .SIS etc mnemonic suffix. Or you can go brute-force and generate the family of 9 (!) instructions with a cgen macro. (There may be other ways too.) - FChE
Hi
Thank you.
About sufficies. Short sufficies (.s, .l, .is, .il) should be converted to
the full one by assembler using ADL (acronim for address & data long) mode
state, which is set by programmer (command line options or directive
.assume ADL=1 or .assume ADL=0), so these short sufficies cannot be just
brutforced...
Another question. Z80 instruction set uses same mnemonic for completely
different (comparing to other cpus) instructions:
LD A,n ; 8-bit load immediate
LD HL,nn ; 16-bit load immediate
LD A,(nn) ; 8-bit direct memory load
LD (IX+5),A ;8-bit indirect indexed memory store
LD (nn),HL ;16-bit direct memory store...
Can it cause ASM parser issues?
Best regards,
Sergey Belyashov
сб, 22 февр. 2020 г., 18:11 Frank Ch. Eigler <fche@redhat.com>:
> Hi -
>
> > The Z80 CPU uses prefix opcodes to change opcode tables and operation
> > registers. For example, <0x21 0x34 0x12> is "LD HL,0x1234", but <0xdd
> 0x21
> > 0x34 0x12> is "LD IX,0x1234". Do I need write both instructions or is it
> > possible to write rule which selects proper instruction set or extract
> > correct register index?
>
> Consider writing prefix opcodes as a normal part of the instruction
> (so include them in the base-insn-bitsize). So you'd need two
> separate instructions, one with and one without. You may be able to
> use cgen macros to generate both flavours from one piece of
> declaration.
>
>
> > Z80 has special rule to form indirect memory operations using index
> > registers. There immediate offset is always third byte of instruction.
> For
> > example: <0xdd 0x34 0x12> is "INC (IX+0x12)", <0xfd 0x36 0xfe 0xab> is
> "LD
> > (IY-0x02),0xAB"... But there are "strange" instructions, where index is
> > placed before opcode itself: <0xdd 0xcb 0x10 0x1e> is "RR (IX+0x10)"
> (<0xcb
> > 0x1e> is "RR (HL)", <0xcb> is opcode prefix, which select another opcode
> > table) and undocumented one <0xdd 0xcb 0x10 0x1f> "RR (IX+0x10),A".
> Should
> > I write 2 instructions types?
>
> Probably, if the same operands are not in the same place.
>
>
> > eZ80 uses four opcode prefixes (.SIS, .SIL, .LIS, .LIL) which set
> operation
> > mode (.IL - long instruction (24 bit immediate), .IS - short instruction
> > (16 bit immediate), .S - 16 bit processing, .L - 24 bit processing):
> <0x40
> > 0x21 0x34 0x12> is "LD.SIS HL,0x1234" and <0x5b 0x21 0x56 0x34 0x12> is
> > "LD.LIL HL,0x123456". These prefixes can be applied to all instructions
> > (but it has no sense for part of instructions). Moreover, assembler
> should
> > support short mode of instructions (.S, .L, .IS, .IL), which is completed
> > by assembler depending on compiling mode (ADL or Z80). Should I generate
> > all possible combinations (9 x instruction_set)? Is there more correct
> > solution?
>
> You may be able to represent tehse opcode prefix bytes as an operand,
> and have a special asm parser/printer that sets them from the .SIS etc
> mnemonic suffix. Or you can go brute-force and generate the family of
> 9 (!) instructions with a cgen macro. (There may be other ways too.)
>
> - FChE
>
>
Hi - > About sufficies. Short sufficies (.s, .l, .is, .il) should be converted to > the full one by assembler using ADL (acronim for address & data long) mode > state, which is set by programmer (command line options or directive > .assume ADL=1 or .assume ADL=0), so these short sufficies cannot be just > brutforced... Aha. If it were just an operand field, a parser could be stateful and fill that in. If it's a whole different opcode prefix/pattern, then a larger custom parser. Try things :-) > Another question. Z80 instruction set uses same mnemonic for completely > different (comparing to other cpus) instructions: > LD A,n ; 8-bit load immediate > LD HL,nn ; 16-bit load immediate > LD A,(nn) ; 8-bit direct memory load > LD (IX+5),A ;8-bit indirect indexed memory store > LD (nn),HL ;16-bit direct memory store... > Can it cause ASM parser issues? I believe there is precedent for different addressing modes with the same mnemonic to result in different opcodes. Sorry I'm not fresh enough with the code base to point them out, but there are a couple of mechanisms. cgen's assembler / disassembler interfaces are hookable enough that you can generally make things work even if the abstract cgen model is not quite enough. - FChE
Hi, I trying to write .cpu file for Z80. Now I stopped in place, how to implement multibyte opcodes. Z80 instructions may have size from one byte to four bytes: <opcode> [<imm8>|<imm16>] <0xED> <opcode> [<imm8>|<imm16>] <0xCB> <opcode> <0xDD/0xFD> <0xCB> <disp8> <opcode> <0xDD/0xFD> <opcode> [<imm8>|<disp8>|<imm16>] <0xDD/0xFD> <opcode> <disp8> <imm8> First format is implemented, now I try second one. Starting from simple instruction RETN (ED 45): (dnf f-0 "whole byte 0" ((MACH z80) all-isas) 7 8) (dnf f-1 "whole byte 1" ((MACH z80) all-isas) 15 8) (dni retn "return from NMI handler" (all-isas UNCOND-CTI) "retn" (+ (f-0 #xED) (f-1 #x45)) () ()) But disassembler do not disassemble 0xED 0x45 sequence. I try declare opcode as one 16-bit field, but CGEN fails: > Error: Instruction has opcode bits outside of its mask. > This usually means some kind of error in the instruction's ifield list. > base mask: 0xffff, base value: 0xed45 > field list: (f-xx 15 16) What I'm doing wrong? whole .cpu file is available here: https://github.com/b-s-a/binutils-gdb/tree/z80-cgen/cpu Best regards, Sergey Belyashov
Hi,
Today I try to implement 0xCB prefixed instructions. I add next
instructions:
(dnf f-0 "whole byte 0" ((MACH z80) all-isas) 7 8)
(dnf f-1 "whole byte 1" ((MACH z80) all-isas) 15 8)
(dnf f-1x "byte 1 field x, bits 7-6" ((MACH z80) all-isas) 15 2)
(dnf f-1y "byte 1 field y, bits 5-3" ((MACH z80) all-isas) 13 3)
(dnf f-1z "byte 1 field z, bits 2-0" ((MACH z80) all-isas) 10 3)
(dni rlc-mhl "rotate left cyclic" (all-isas) "rlc (hl)" (+ (f-0 #xCB)
(f-1x 0) (f-1y 0) (f-1z 6)) () ())
(dni rlc-r "rotate left cyclic" (all-isas) "rlc $rs1" (+ (f-0 #xCB)
(f-1x 0) (f-1y 0) rs1) () ())
(dni rrc-r "rotate right cyclic" (all-isas) "rrc $rs1" (+ (f-0 #xCB)
(f-1x 0) (f-1y 1) rs1) () ())
And disassembler disassemble all CB prefixed instructions as RLC <r>. So it
looks like explicit field value is not work. Next I see, what is generated
for these instructions in the z80-opc.c file:
/* retn */
{
{ 0, 0, 0, 0 },
{ { MNEM, 0 } },
& ifmt_retn, { 0x132 }
},
/* rlc $rs1 */
{
{ 0, 0, 0, 0 },
{ { MNEM, ' ', OP (RS1), 0 } },
& ifmt_rlc_r, { 0xcb }
},
/* rlc (hl) */
{
{ 0, 0, 0, 0 },
{ { MNEM, ' ', '(', 'h', 'l', ')', 0 } },
& ifmt_rlc_mhl, { 0xd1 }
},
Why fields of different bytes are OR'ed?!?
Next, I try to specify following decode-splits for ISA:
(decode-splits
(f-y () ((s-reg8 (0 1 2 3 4 5 7)) (s-mhl (6))))
(f-z () ((s-reg8 (0 1 2 3 4 5 7)) (s-mhl (6))))
)
But CGEN fails with error:
machs: all
isas: all
options:
trace:
diags:
Including file ../../opcodes/../cpu/simplify.inc ...
ERROR: Wrong type argument in position 2: 3
No backtrace available.
decode-splits is present only one arm.cpu file, but it commented out. Is it
works?
Best regards,
Sergey Belyashov
вт, 24 мар. 2020 г. в 00:44, Sergey Belyashov <sergey.belyashov@gmail.com>:
> Hi,
> I trying to write .cpu file for Z80. Now I stopped in place, how to
> implement multibyte opcodes. Z80 instructions may have size from one byte
> to four bytes:
> <opcode> [<imm8>|<imm16>]
> <0xED> <opcode> [<imm8>|<imm16>]
> <0xCB> <opcode>
> <0xDD/0xFD> <0xCB> <disp8> <opcode>
> <0xDD/0xFD> <opcode> [<imm8>|<disp8>|<imm16>]
> <0xDD/0xFD> <opcode> <disp8> <imm8>
>
> First format is implemented, now I try second one. Starting from simple
> instruction RETN (ED 45):
> (dnf f-0 "whole byte 0" ((MACH z80) all-isas) 7 8)
> (dnf f-1 "whole byte 1" ((MACH z80) all-isas) 15 8)
> (dni retn "return from NMI handler" (all-isas UNCOND-CTI) "retn" (+
> (f-0 #xED) (f-1 #x45)) () ())
>
> But disassembler do not disassemble 0xED 0x45 sequence. I try declare
> opcode as one 16-bit field, but CGEN fails:
> > Error: Instruction has opcode bits outside of its mask.
> > This usually means some kind of error in the instruction's ifield list.
> > base mask: 0xffff, base value: 0xed45
> > field list: (f-xx 15 16)
>
> What I'm doing wrong?
>
> whole .cpu file is available here:
> https://github.com/b-s-a/binutils-gdb/tree/z80-cgen/cpu
>
> Best regards,
> Sergey Belyashov
>