-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathZSM.TXT
565 lines (405 loc) · 18.1 KB
/
ZSM.TXT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
ZSM 3.2, a CP/M Z80 assembler
-------------------------------------
| Changes from version 2.8 documentation have a 'change bar'
| <<< here.
;! ZSM 3.0 is similar to the earlier versions of ZSM (including
2.9 T) but the error checking has been made more rigorous. I
have used the mark ';!' to indicate the changes from the
previous version 2.9 T. C.G.Maxfield.
% Comments for version 3.1 have a '%'
% <<< here (what a mess!).
ZSM is an assembler for the Z80 microprocessor. It uses standard
Zilog/Mostek mnemonics, supports conditional assembly and
produces an Intel HEX file suitable for loading with the CP/M LOAD
utility. ZSM is a disk based assembler, i.e. source code is read
from disk, the resulting object code is written to disk and an
optional print file can be written to disk. Alternatively the
print file can be redirected to the console.
1. Using the assembler.
-----------------------
The assembler is initiated by typing:
ZSM filename.pqr
This takes the file 'filename.ZSM' and assembles it according to
the parameters 'p','q' and 'r' and the options chosen. The
parameters must be selected as follows:
p - the disk drive containing the source code,
'filename.ZSM'. A to P or @ for default drive.
q - the disk drive where the object code, 'filename.HEX' is
to be written. A to P or @ for default drive, Z if not
required.
r - the disk drive where the listing is to be written,
'filename.PRN'. A to O or @ for default drive, P to
the list device, X to the console, Y to the console
with errors to the printer, Z to suppress listing.
For example assembling the file TEST.ZSM:-
ZSM TEST.AAB
This expects the file TEST.Z80 on drive A, will write the object
code file, TEST.HEX to drive A and the listing file, TEST.PRN to
drive B.
| 2.9 If no filename is found or there is an error, the user
| will be reminded of all these conventions.
| 2.9 Now prints out a message at the start of each pass & sort
| of symbols.
| 2.9 The default origin is now 0100h, not 0000h.
| 2.9 Drive O: now works for .prn file.
2. Assembler syntax
-------------------
2.1 ASSEMBLER MNEMONICS
The assembler recognises all standard Z80 mnemonics as defined in
the Z80 CPU Technical Manual. The following mnemonics are
recognised in both forms shown.
ADC A,s ADC s
ADD A,s ADD s
SBC A,s SBC s
Where 's' can be a single register, (HL), (IX+d), (IY+d) or n.
Where 'n' is a constant, and 'd' is a displacement.
;! Earlier versions of ZSM (i. e. before ver 3.0) accepted AND A,s
CP A,s OR A,s SUB A,s and XOR A,s as valid instructions. As these
are non-standard, they now generate a syntax error.
2.2 LABELS
Labels may be up to 11 characters long. The first character of
the label must be alphabetic (i.e. A-Z) or '_' or '$'. A colon,
':' following the label is optional, both for labels and equates.
| 2.9 allows '%' in labels
% 3.1 disabled '%' in labels and
% enabled '_' and '$' as the first character in labels (as
% stated in the doc. some versions ago!)
2.3 CONSTANTS
ZSM allows binary, octal, decimal, hexadecimal and ASCII
constants according to the following conventions:
Binary - number formed from binary digits (0,1) and terminated by
the character 'B'. Range 0000000000000000B to 1111111111111111B.
Example: LD HL,10001111101101B
Octal - number formed from octal digits (0-7) and terminated by
the character 'Q'. Range 000000Q to 177777Q.
Example: LD HL,23670Q
Decimal - number formed from decimal digits (0-9) and EITHER left
unterminated or terminated by the character 'D'.
Range: 0 to 65535.
Example: LD HL,32145
Hexadecimal - number formed from hexadecimal digits (0-9 and A-F)
and terminated by the character 'H'. A hex number beginning with
a letter must be preceded by a 0 to distinguish it from a label
or register name. Range 0000H to FFFFH.
Example: LD HL,0A3FH
ASCII - number formed from ASCII value of characters enclosed in
single quotes. Range ' ' to '~' or 20H to 7EH including all
alphanumerics and punctuation.
| Use "''" to include a "'" in a string
Examples: LD HL,'Wk'
LD A,'*'
The $ sign used as a constant represents the current value of the
program counter.
| 2.9 Using '$' in long DB / DWs now works properly, even when
| subtracting (or multiplying etc) it...
2.4 EXPRESSION EVALUATION
Operands in instructions and pseudo-ops may consist of arithmetic
expressions which are evaluated at assembly time and the
calculated value used as part of the object code. The following
operators may be used to form expressions:
+ Addition
- Subtraction (or unary Negation)
* Multiplication
/ Division
.MOD. Modulus
| \ Alternate modulus for 2.9 -- 2.8 uses %
% % Version 3.1 can use % for modulus too.
| > or .GT. Greater Than. X.GT.Y true if X greater than Y.
.GE. Greater than or Equal. X.GE.Y true if X
greater than or equal to Y.
| < or .LT. Less Than. X.LT.Y true if X less than Y.
| .LESS. Signed Less than -- others are unsigned (2.9)
.LE. Less than or Equal. X.LE.Y true if X less
than or equal to Y.
= or .EQ. Equal. X.EQ.Y true if X equals Y.
.NE. Not Equal. X.NE.Y true if X not equal to Y.
| .SHL. n Shift Left n (unsigned) bits.
| .SHR. n Shift Right n (unsigned) bits.
.NOT. Logical NOT (unary)
.AND. Logical AND
.OR. Logical OR
.XOR. Logical Exclusive OR
.LOW. Low byte of expression (.MOD. 256)
.HIGH. High byte of expression (.SHR. 8)
Expressions are evaluated left to right with no precedence. No
parentheses can be used in expressions so some care is required
to ensure that expressions are correctly formed.
;! These conventions now also apply to the Unary expressions .NOT.
.LOW. and .HIGH. Versions of ZSM earlier than ver 3.0 made
exceptions of these operators. If they are used in your favourite
program, these operators will have to be changed.
;! However it is now possible to use instructions like:-
LD A,LABEL .HIGH.
;! The old version:-
LD A,.HIGH. LABEL
;! used to result in an error, rather than loading A with the high
byte of the 16 bit value given to LABEL.
;! I regret that, in general, negative numbers must still be at the
start of an evaluation string. This is because two consecutive
arithmetic operators is meaningless and therefore an error. For
instance:-
A + * B is ambiguous. Should A be added to B or Multiplied by it?
Hence A * -B is also ambiguous. Use -B * A
2.5 PSEUDO-OPCODES
DB or DEFB (define byte)
The DB pseudo-op tells the assembler to reserve a byte or string
of bytes with specific values. The bytes may be defined as
constants, expressions as described earlier or as already defined
symbols.
<label>: DB <item or list of items>
For example:
DB 3,-5,34+LABEL,'A'
DS or DEFS (define storage)
This tells the assembler to reserve a specified number of bytes
for storage. Note that the data stored in the bytes is not
defined.
DW or DEFW (define word)
This is exactly the same as the DB Pseudo-op except that the
data is stored in words (2 bytes each) rather than bytes.
END (end of assembly)
This pseudo-op is used to terminate assembly of a block of source
code.
ENDIF (end of IF definition)
Used to terminate a block of conditionally assembled code. See IF
Pseudo-op for further details.
EQU (equate)
The EQU pseudo-op assigns a value to a label or symbol. The
format is:
label: EQU <item>
Label is the name of the symbol and item is any of: a constant,
an address, a label or an expression. Once the value of the
symbol is assigned it is in effect for the entire source program.
FORM (form feed)
Forces a new page in the listing.
| also PAGE and EJECT with the same effect.
| 2.9 If the Z80 CPU version running on a CP/M+ machine, the
| time and date is added to the page heading. If the 'CP/M
| date' hasn't been set, only the time is printed.
| 2.9 If the .prn output is going to the console, no headers are
| generated.
| TITLE
| Allows the user to add a descriptive line to each page heading.
| Forces a new page. A blank title is allowed, only the source file
name and page number will be included.
| TITLE <A line of description!>
IF (begin conditional assembly)
The IF, ELSE and ENDIF pseudo-ops define a sequence of assembly
language statements which are to be included or excluded during
the assembly. The form is:
IF <expression>
statement #1
statement #2
.....
statement #n
[ELSE
.....
..... ]
ENDIF
Conditionals may be nested up to n levels deep. Values used in
the expression must be defined before the IF statement. When the
assembler finds an IF pseudo-op the expression is evaluated. If
the expression evaluates to a logical TRUE (non-zero) then the
statements following, up to the ENDIF are included in the
assembly. The optional ELSE pseudo-op allows alternate code to be
generated when the opposite condition exists. An ELSE is always
related to the most recent active IF.
| n levels = at least eight (now an equate in zsm.zsm -- 'maxif')
IF <expr1> -----------+
|
IF <expr2> ------+ |
| |
ELSE ---------------+ |
| |
ENDIF --------------+ |
|
IF <expr3> -------+ |
| |
ENDIF --------------+ |
|
ENDIF -------------------+
LIST (use following options in listing)
This is used to control what parts of the assembly listing get
sent to the listing file. The word LIST is followed by a string
of option words separated by commas.
| 2.9 Multiple list options now work!
| 2.9 The listing starts using the default values -- 2.8 used
| those in use at the end of pass 1.
LIST OFF
Suppresses the listing until a LIST ON command.
LIST ON (default)
Turns on the listing file after a LIST OFF statement.
LIST COND (default)
Forces generation and printing of all blocks of code which
are part of conditional assemblies whether they are
assembled or not.
LIST NOCOND
Suppresses listing of IF, ELSE and ENDIF statements and any
conditionally assembled code which is NOT included in the
assembly, i.e. only the code actually assembled is shown in
the listing.
LIST SYMBOL (default)
Generate a symbol table at the end of the listing file.
LIST NOSYMBOL
Suppress printing of a symbol table at the end of the
listing file.
LIST TABS (default)
Tab characters (ASCII 9) are to be used in the listing file.
LIST NOTABS
Do not use tabs in the listing file.
| 2.9 LIST SORT (default)
| Sort any symbol table produced.
| 2.9 LIST NOSORT
| Order of symbols in table is their order in the source file.
| This is much faster for large tables...
| 2.9 also has:
| ASSERT (test all is well at assembly time)
| This is used to check for illogical conditions at assembly time
| such as program sections too long, silly equates etc.
| ASSERT <expression>
| If the expression evaluates to false (zero), an error results.
| The result is only used during pass 2, so forward references are
| safe!
;! Please see Appendix A for further details of Ian Watter's
ASSERT pseudo-op. C.G.M.
2.6 COMMENTS
Remarks or comments are free format including any printable ASCII
character as long as the comment is preceded by a semicolon, ';'.
The comment may follow an opcode, operand or label or may exist
on a line by itself.
3. Error Messages
ZSM generates a number of error messages while assembling to
inform you of its progress. They fall into two categories: errors
found while setting up files for assembly operation and those
encountered while assembling the file. The first type of error
message will be one of the following:
Source (.ZSM) file not found.
Unable to create/open object (.HEX) file.
Unable to create/open output (.PRN) file.
The first message is generated when the filename specified in the
command line cannot be found on the selected disk. The other
messages occur while the output (HEX and PRN) files are being set
up, usually the disk or directory is full. These errors are sent
only to the console and the assembly is aborted.
| 2.9 Some help is also given to get it right next time.
The following errors can occur during the assembly process. The
offending source line is displayed on the console, followed by
the error message. If a listing file has been selected the error
message appears in the listing on the line following the error.
Errors are displayed even if the listing has been disabled using
the 'LIST OFF' pseudo-op.
"Too many IF statements"
Only 8 levels of nested IF statements are allowed now
"ENDIF without matching IF statement"
IF and ENDIF should always be paired to indicate the start
and end of a section of conditional code.
"ELSE without matching IF statement"
The ELSE pseudo-op should only appear within a section of
conditional code between IF and ENDIF.
"Relative jump range error"
The address specified in a relative jump instruction is out
of the range -128 to +127.
"Expression error"
This error is caused by a badly formed expression. Note that
brackets are not allowed in expressions.
"Illegal opcode"
The assembler cannot recognise the instruction.
"Multiple definition"
The symbol has already been defined.
"Syntax error"
This error message covers a multitude of sins. It is usually
caused by misspelling or omission of a delimiter such as a
comma or semicolon.
"Undefined symbol"
The symbol used in the instruction or expression has not
been defined.
"Value error"
This error appears when the value of a symbol or expression
exceeds the range allowable. For example an index register
displacement value must be in the range +127 to -128.
"Symbol Table Overflow"
"Divide by Zero"
The expression being evaluated contains a division by zero.
| 2.9 "Label Error"
| The label is malformed or in the wrong place etc.
| 2.9 "Assertion false"
| The expression in an ASSERT test evaluated to false (zero).
Other version 2.9 notes
-----------------------
Many thanks to those who have gone before me, I hope y'all think what
I have done is an improvement! There's still LOTS that could be done,
but I leave that to you, dear reader.
For a start, the symbol table really ought to be in a tree format or
hashed for faster access. The bubble sort routine that sorts it just
has to be put out of its (and your) misery soon. A proper expression
analyser (none of this just left to right stuff) would be nice, as
would macros. The code generation section can be made to go much
faster too.
In fact, the whole thing could and should be re-written. More likely,
you will stomp on the couple of creepy crawlies mentioned in the test
file. Then you'll think, "Hmmm, THAT bit of code needs changing."
Then another bit, then another bit, then another...
I've enjoyed touching ZSM up. Hope you do too.
Good luck!
Ian
Changes made in version 3.1
---------------------------
- Removed feature level for ZSM version.
- Removed date/time code.
- Enabled '_' and '$' as the first character in labels (as stated
in the doc. some versions ago!).
- Modulus can be '%' too, as in previous versions.
- Disabled '%' as valid character for labels.
- Modified usage explanation.
By Miguel Garcia / FloppySoftware - 30 Nov 2016.
http://www.floppysoftware.es
floppysoftware@gmail.com
Changes made in version 3.2
---------------------------
- Solved bug in rotate op-codes (rl r, rlc r, rr r, rrc r, sla r,
sra r, srl r): op-codes with 'c' register were translated to
machine code as if the 'e' register was used instead. See S24
section.
- Added patch from Ed, to restore support for date/time in titles
in CP/M 3: "This patched version restores date/time code as
assembly-time option (see DATE EQU). Now works with 8080 or Z80.".
By Miguel Garcia / FloppySoftware - 01 Jan 2017.
http://www.floppysoftware.es
floppysoftware@gmail.com
APPENDIX A.
A few further words about Ian Watter's ASSERT pseudo-op.
It is best thought of as an 'alarm contact' that can be used by the
programmer for any purpose that comes to mind. It's use is best
illustrated by the example below that has been extracted from the
source code for ZSM 2.9 T :-
;
endboot: ds 1
;
INBUF: equ 100h ;.ZSM INPUT BUFFER
OUTBUF: equ inbuf+buflen ;.PRN OUTPUT BUFFER
OUTBF2: equ outbuf+seclen ;.HEX OUTPUT BUFFER
;
ORG outbf2+seclen ;end of I/O BUFFER SPACE
;
ASSERT $ > endboot ; check boot-up code not too big
;
It will be noted that the boot-up code preceds the example shown
above, and that the base address for the main code that follows the
example, is set by the ORG statement.
If additions are made to the boot code during program development,
so that the address of 'endboot:' is now greater than that set by
the ORG statement, ASSERT will generate an error during assembly;
thus warning the programmer that the the start of the main code has
been overwritten, and adjustments will have to be made.
By giving it a suitable expression to test, ASSERT can be used to
check for other conditions, during assembly. The essential point to
remember is, the expression must evaluate to zero to cause an alarm.
In the example above, the 'greater than' symbol serves this
function.
It is often necessary to determine the current starting address of a
particular routine, so that it can be de-bugged. Placing an ASSERT
pseudo-op, with no expression following it, at the start of the
routine in question, will cause a 'benign error' at this point, and
so reveal its address during assembly.
C.G.M. March 1991.
e in question, will cause a 'benign error' at this point, and
so reveal its address during assemb