zmac - Z-80 Macro Cross Assembler
zmac has been around for a long time. My version runs under Windows (XP or Vista and probably older versions), has a few bug fixes but is most notable for the extensions I've added. There are two new psuedo-ops.
| assert | expr | Stop assembly if expr is non-zero. |
| sett | expr | Set the current T-state count to expr |
| setocf | expr | Set the current opcode fetch count to expr |
| tstate | expr | Old form of sett |
And a number of new operators and functions.
| == | Equality |
| != | Inequality |
| <= | Less-than or equal to |
| >= | Greater-than or equal to |
| < | Less-than |
| > | Greater-than |
| ! | Logical not |
| t(expr) | Current count of T-states up to memory location expr |
| tilo(expr) | Low count of T-states used by instruction as memory location expr |
| tihi(expr) | High count of T-states used by instruction as memory location expr |
| ocf(expr) | Current count of opcode fetches up to memory location expr |
The best description of the T-state counting macros can be found at the end of my cycle counting tutorial. Might also explain why you would want such a feature. setocf and ocf() are newer features not covered there. They're needed when counting clock cycles on the TRS-80 Model 4 when it runs in high speed (4 MHz) mode. While the Z-80 mostly runs twice as fast in that the opcode fetch portion of each instruction is slowed down by 2 wait states. Code on the Model 1 or Model 3 (or Model 4 running in Model 3 mode) can be timed like this:
code: ld a,(de) ld b,(hl) add a,b time equ t($)-t(code)The first two instructions take 7 T-states, the 3rd 4 T-states so zmac will set time equal to 18. But if you need cycle-accurate counts on a Model 4 you'll have to do this:
code: ld a,(de) ld b,(hl) add a,b time equ t($)-t(code)+2*[ocf($)-ocf(code)]As before we get a base time of 18 T-states but in this case each instruction also takes an opcode fetch thus the equation will add an additional 6 T-states and zmac will set time to 24.
While most instructions require only one opcode fetch many others take more. All instructions require at least one opcode fetch so ocf() will be at least a count of instructions.
Be forewarned that sometimes the T-state counting goes off. I'm not sure of the cause, but sometimes the count comes out way off with t($) giving values thousands of times different than expected. This can generally be fixed by putting a tstate 0 before the offending code block. That suggests the error has something to do with a multi-pass problem but at any rate keep this in mind if your timing suddenly goes off.
If you'd like any of these features in your version of zmac or would like the source code, just drop me a line at the e-mail address below.
George Phillips, May 3, 2011. gp2000 -at- shaw.ca