Skip to content

Commit ddd6aef

Browse files
committed
Add ZX Next ASM capabilities for ZXBasm
1 parent ccfa48d commit ddd6aef

File tree

8 files changed

+180
-12
lines changed

8 files changed

+180
-12
lines changed

api/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def init():
6868
OPTIONS.add_option('explicit', bool, False)
6969
OPTIONS.add_option('Sinclair', bool, False)
7070
OPTIONS.add_option('strict', bool, False) # True to force type checking
71+
OPTIONS.add_option('zxnext', bool, False) # True to enable ZX Next ASM opcodes
7172

7273

7374
init()

asmlex.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,31 @@
9393
'xor': 'XOR',
9494
}
9595

96+
zx_next_mnemonics = {
97+
x.lower(): x for x in [
98+
"LDIX",
99+
"LDWS",
100+
"LDIRX",
101+
"LDDX",
102+
"LDDRX",
103+
"LDPIRX",
104+
"OUTINB",
105+
"MUL",
106+
"SWAPNIB",
107+
"MIRROR",
108+
"NEXTREG",
109+
"PIXELDN",
110+
"PIXELAD",
111+
"SETAE",
112+
"TEST",
113+
"BSLA",
114+
"BSRA",
115+
"BSRL",
116+
"BSRF",
117+
"BRLC"
118+
]
119+
}
120+
96121
pseudo = { # pseudo ops
97122
'align': 'ALIGN',
98123
'org': 'ORG',
@@ -154,6 +179,7 @@
154179
tuple(regs8.values()) +
155180
tuple(regs16.values()) +
156181
tuple(flags.values()) +
182+
tuple(zx_next_mnemonics.values()) +
157183
tuple(preprocessor.values())
158184
)
159185

@@ -162,7 +188,8 @@
162188
regs16.keys()).union(
163189
regs8.keys()).union(
164190
pseudo.keys()).union(
165-
reserved_instructions.keys())
191+
reserved_instructions.keys()).union(
192+
zx_next_mnemonics.keys())
166193

167194

168195
def get_uniques(l):
@@ -273,6 +300,11 @@ def t_INITIAL_ID(self, t):
273300
if t.type is not None:
274301
return t
275302

303+
if OPTIONS.zxnext.value:
304+
t.type = zx_next_mnemonics.get(id_)
305+
if t.type is not None:
306+
return t
307+
276308
t.type = regs16.get(id_, 'ID')
277309
if t.type == 'ID':
278310
t.value = tmp # Restores original value

asmparse.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,7 +1455,12 @@ def assemble(input_):
14551455
if MEMORY is None:
14561456
MEMORY = Memory()
14571457

1458-
parser.parse(input_, lexer=LEXER, debug=OPTIONS.Debug.value > 2)
1458+
if OPTIONS.zxnext.value:
1459+
parser_ = zxnext_parser
1460+
else:
1461+
parser_ = parser
1462+
1463+
parser_.parse(input_, lexer=LEXER, debug=OPTIONS.Debug.value > 2)
14591464
if len(MEMORY.scopes):
14601465
error(MEMORY.scopes[-1], 'Missing ENDP to close this scope')
14611466

@@ -1541,4 +1546,13 @@ def main(argv):
15411546
generate_binary(OPTIONS.outputFileName.value, OPTIONS.output_file_type)
15421547

15431548

1544-
parser = api.utils.get_or_create('asmparse', lambda: yacc.yacc(debug=OPTIONS.Debug.value > 2))
1549+
# Z80 only ASM parser
1550+
parser = api.utils.get_or_create('asmparse',
1551+
lambda: yacc.yacc(start="start", debug=OPTIONS.Debug.value > 2))
1552+
1553+
# needed for ply
1554+
from zxnext import * # noqa
1555+
1556+
# ZXNEXT extended OPcodes parser
1557+
zxnext_parser = api.utils.get_or_create('zxnext_asmparse',
1558+
lambda: yacc.yacc(start="start", debug=OPTIONS.Debug.value > 2))

parsetab/tabs.dbm.bak

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
'zxbppparse', (0, 68810)
2-
'zxbparser', (69120, 707013)
3-
'asmparse', (776192, 250068)
2+
'asmparse', (69120, 250081)
3+
'zxnext_asmparse', (319488, 280962)
4+
'zxbparser', (600576, 707013)

parsetab/tabs.dbm.dat

275 KB
Binary file not shown.

parsetab/tabs.dbm.dir

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
'zxbppparse', (0, 68810)
2-
'zxbparser', (69120, 707013)
3-
'asmparse', (776192, 250068)
2+
'asmparse', (69120, 250081)
3+
'zxnext_asmparse', (319488, 280962)
4+
'zxbparser', (600576, 707013)

zxbasm.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import argparse
1717

1818
import asmparse
19-
from asmparse import Asm, Expr, Container
2019
import zxbpp
2120

2221
import api.config
@@ -66,6 +65,9 @@ def main(args=None):
6665
o_parser.add_argument("-b", "--bracket", action="store_true", default=False,
6766
help="Allows brackets only for memory access and indirections")
6867

68+
o_parser.add_argument('-N', "--zxnext", action="store_true", default=False,
69+
help="Enable ZX Next extra ASM opcodes!")
70+
6971
o_parser.add_argument("--version", action="version", version="%(prog)s " + VERSION)
7072

7173
options = o_parser.parse_args(args)
@@ -83,6 +85,7 @@ def main(args=None):
8385
OPTIONS.StdErrFileName.value = options.stderr
8486
OPTIONS.memory_map.value = options.memory_map
8587
OPTIONS.bracket.value = options.bracket
88+
OPTIONS.zxnext.value = options.zxnext
8689

8790
if options.tzx:
8891
OPTIONS.output_file_type.value = 'tzx'
@@ -123,15 +126,15 @@ def main(args=None):
123126
current_org = max(asmparse.MEMORY.memory_bytes.keys() or [0]) + 1
124127

125128
for label, line in asmparse.INITS:
126-
expr_label = Expr.makenode(Container(asmparse.MEMORY.get_label(label, line), line))
127-
asmparse.MEMORY.add_instruction(Asm(0, 'CALL NN', expr_label))
129+
expr_label = asmparse.Expr.makenode(asmparse.Container(asmparse.MEMORY.get_label(label, line), line))
130+
asmparse.MEMORY.add_instruction(asmparse.Asm(0, 'CALL NN', expr_label))
128131

129132
if len(asmparse.INITS) > 0:
130133
if asmparse.AUTORUN_ADDR is not None:
131-
asmparse.MEMORY.add_instruction(Asm(0, 'JP NN', asmparse.AUTORUN_ADDR))
134+
asmparse.MEMORY.add_instruction(asmparse.Asm(0, 'JP NN', asmparse.AUTORUN_ADDR))
132135
else:
133136
asmparse.MEMORY.add_instruction(
134-
Asm(0, 'JP NN', min(asmparse.MEMORY.orgs.keys()))) # To the beginning of binary. Ehem...
137+
asmparse.Asm(0, 'JP NN', min(asmparse.MEMORY.orgs.keys()))) # To the beginning of binary
135138

136139
asmparse.AUTORUN_ADDR = current_org
137140

zxnext.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# -*- coding: utf-8 -*-
2+
3+
__all__ = [
4+
'p_mul_d_e',
5+
'p_simple_instruction',
6+
'p_add_reg16_a',
7+
'p_JP_c',
8+
'p_bxxxx_de_b',
9+
'p_add_reg_NN',
10+
'p_test_nn',
11+
'p_nextreg_expr',
12+
'p_nextreg_a',
13+
'p_push_imm'
14+
]
15+
16+
17+
import asmparse
18+
19+
20+
def p_mul_d_e(p):
21+
""" asm : MUL D COMMA E
22+
"""
23+
p[0] = asmparse.Asm(p.lineno(1), 'MUL D,E')
24+
25+
26+
def p_simple_instruction(p):
27+
""" asm : LDIX
28+
| LDWS
29+
| LDIRX
30+
| LDDX
31+
| LDDRX
32+
| LDPIRX
33+
| OUTINB
34+
| SWAPNIB
35+
| MIRROR
36+
| PIXELDN
37+
| PIXELAD
38+
| SETAE
39+
"""
40+
p[0] = asmparse.Asm(p.lineno(1), p[1])
41+
42+
43+
def p_add_reg16_a(p):
44+
""" asm : ADD HL COMMA A
45+
| ADD DE COMMA A
46+
| ADD BC COMMA A
47+
"""
48+
p[0] = asmparse.Asm(p.lineno(1), 'ADD {},A'.format(p[2]))
49+
50+
51+
def p_JP_c(p):
52+
""" asm : JP LP C RP
53+
"""
54+
p[0] = asmparse.Asm(p.lineno(1), 'JP (C)')
55+
56+
57+
def p_bxxxx_de_b(p):
58+
""" asm : BSLA DE COMMA B
59+
| BSRA DE COMMA B
60+
| BSRL DE COMMA B
61+
| BSRF DE COMMA B
62+
| BRLC DE COMMA B
63+
"""
64+
p[0] = asmparse.Asm(p.lineno(1), '{} DE,B'.format(p[1]))
65+
66+
67+
def p_add_reg_NN(p):
68+
""" asm : ADD HL COMMA expr
69+
| ADD DE COMMA expr
70+
| ADD BC COMMA expr
71+
| ADD HL COMMA pexpr
72+
| ADD DE COMMA pexpr
73+
| ADD BC COMMA pexpr
74+
"""
75+
p[0] = asmparse.Asm(p.lineno(1), 'ADD {},NN'.format(p[2]), p[4])
76+
77+
78+
def p_test_nn(p):
79+
""" asm : TEST expr
80+
| TEST pexpr
81+
"""
82+
p[0] = asmparse.Asm(p.lineno(1), 'TEST N', p[2])
83+
84+
85+
def p_nextreg_expr(p):
86+
""" asm : NEXTREG expr COMMA expr
87+
| NEXTREG expr COMMA pexpr
88+
| NEXTREG pexpr COMMA expr
89+
| NEXTREG pexpr COMMA pexpr
90+
"""
91+
p[0] = asmparse.Asm(p.lineno(1), 'NEXTREG N,N', (p[2], p[4]))
92+
93+
94+
def p_nextreg_a(p):
95+
""" asm : NEXTREG expr COMMA A
96+
| NEXTREG pexpr COMMA A
97+
"""
98+
p[0] = asmparse.Asm(p.lineno(1), 'NEXTREG N,A', p[2])
99+
100+
101+
def p_push_imm(p):
102+
""" asm : PUSH expr
103+
| PUSH pexpr
104+
"""
105+
# Reverse HI | LO => X1 = (X0 & 0xFF) << 8 | (X0 >> 8) & 0xFF
106+
mknod = asmparse.Expr.makenode
107+
cont = lambda x: asmparse.Container(x, p.lineno(1))
108+
ff = mknod(cont(0xFF))
109+
n8 = mknod(cont(8))
110+
111+
expr = mknod(
112+
cont('|'),
113+
mknod(cont('<<'), mknod(cont('&'), p[2], ff), n8),
114+
mknod(cont('&'), mknod(cont('>>'), p[2], n8), ff)
115+
)
116+
p[0] = asmparse.Asm(p.lineno(1), 'PUSH NN', expr)

0 commit comments

Comments
 (0)