| back |  | Last regenerated: 2022-04-20 17:31:36 kio

# zasm - Z80 Assembler – Version 4.4

# Assembler directives

[<prev] [next>]

| ### #test
    #test <name>,<start>,<size>
Define code segment for automated tests after successful assembly. The test code will be loaded on top of the assembled code and executed. During execution i/o addresses are monitored and compared with supplied values. Finally – or at any time during the test – registers and the cpu cycle count can be compared against expected values. There can be any number of tests in a test segment and there can be any number of test segments which are loaded and executed separately. Test errors are handled like assembly errors. Only Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if all tests pass the assembled code is finally written. #### Technical Specification of the Test Code Runner ##### CPU emulation zasm can emulate the 8080, Command Line Options: --z80 Pseudo instructions: .z80, .z180 and .8080 Targets: #target Z80 Z80 and Command Line Options: --z180 Pseudo instructions: .z80, .z180 and .8080 Z180 cpu. The instruction Pseudo instructions: defl, set and '=' Labels: SET set is limited to the selected CPU, eventually modified by Differences from v3 to v4: Command line options Command Line Options Command Line Options: Command line options command line options --Command Line Options: --ixcbxh, .ixcbxh, _ixcbxh_ --ixcbr2, .ixcbr2, _ixcbr2_ Commands for command line options: --ixcbxh, .ixcbxh, _ixcbxh_ --ixcbr2, .ixcbr2, _ixcbr2_ixcbr2 or --Command Line Options: --ixcbxh, .ixcbxh, _ixcbxh_ --ixcbr2, .ixcbr2, _ixcbr2_ Commands for command line options: --ixcbxh, .ixcbxh, _ixcbxh_ --ixcbr2, .ixcbr2, _ixcbr2_ixcbxh. Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif If an unimplemented / illegal instruction is executed, the emulation stops with an error and the test fails. ###### 8080 emulation The 8080 cpu has no unhandled/undocumented opcodes, but some opcodes have aliases which were used by the Command Line Options: --z80 Pseudo instructions: .z80, .z180 and .8080 Targets: #target Z80 Z80 for additional functions, e.g. relative jumps, 2nd register Pseudo instructions: defl, set and '=' Labels: SET set and prefix opcodes. Only the official opcodes, which are also those which are generated by zasm, are allowed. Execution of an alias opcode, which was reused by the Command Line Options: --z80 Pseudo instructions: .z80, .z180 and .8080 Targets: #target Z80 Z80, is handled like an illegal opcode and will terminate the test. This is to prevent you from accidentially writing code which will not run on a Command Line Options: --z80 Pseudo instructions: .z80, .z180 and .8080 Targets: #target Z80 Z80. ###### Z80 emulation Widely used undocumented opcodes are always executed without generating an error. These are SLL and access to the upper and lower half of index registers in LD and arithmetical/logical operations. Illegal index register opcodes after after prefix IX/IY + prefix 0xCB are allowed, Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if the corresponding Differences from v3 to v4: Command line options Command Line Options Command Line Options: Command line options command line option --Command Line Options: --ixcbxh, .ixcbxh, _ixcbxh_ --ixcbr2, .ixcbr2, _ixcbr2_ Commands for command line options: --ixcbxh, .ixcbxh, _ixcbxh_ --ixcbr2, .ixcbr2, _ixcbr2_ixcbr2 or --Command Line Options: --ixcbxh, .ixcbxh, _ixcbxh_ --ixcbr2, .ixcbr2, _ixcbr2_ Commands for command line options: --ixcbxh, .ixcbxh, _ixcbxh_ --ixcbr2, .ixcbr2, _ixcbr2_ixcbxh was Pseudo instructions: defl, set and '=' Labels: SET set. Then they are performed according to this setting. [TODO: the timing of ixcbih opcodes is unclear] All other undocumented / illegal opcodes are rejected and will terminate the test with an error. ###### Z180 emulation All Command Line Options: --z180 Pseudo instructions: .z80, .z180 and .8080 Z180 opcodes are emulated and the different timing is implemented. The Command Line Options: --z180 Pseudo instructions: .z80, .z180 and .8080 Z180 traps illegal instructions and so does the emulation. [TODO: the exact behavior of the SLP opcode is unclear] The test code is executed by a variant of Kio's Command Line Options: --z80 Pseudo instructions: .z80, .z180 and .8080 Targets: #target Z80 Z80 engine. The emulation speed is approx. 800MHz@Command Line Options: --z80 Pseudo instructions: .z80, .z180 and .8080 Targets: #target Z80 Z80 per GHz@Host (2.6GHz on 3.2GHz AMD Ryzen5 2400G) or let's say, depending on the emulated system and the speed of your host, the emulated Command Line Options: --z80 Pseudo instructions: .z80, .z180 and .8080 Targets: #target Z80 Z80 is running 1000 times faster than the original. :-) I found out that the emulation speed is very sensitive to the loading position of the Command Line Options: --z80 Pseudo instructions: .z80, .z180 and .8080 Targets: #target Z80 Z80 engine and can vary widely - for my PC from 1MHz emulated speed to 2.5MHz! I'll try to check the speed before releases of zasm but will probably frequenty fail to do so. After all it can be completely different on someone else's PC. The emulation of the Command Line Options: --z80 Pseudo instructions: .z80, .z180 and .8080 Targets: #target Z80 Z80 is very precise but i cannot guarantee correctness to the last bit and cycle. Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif If you find any difference please report a bug. Replication of the undefined behavior of flags is 80% exact. ##### Memory, interrupts and i/o The assembled code is loaded into 64kB ram, each segment at the address defined in the Assembler directives: #code Including C Source Files: #code#code directive, ignoring possible overlap. Finally the test segment is loaded, again happily overwriting already loaded segments. Memory mapping is not supported. Wait states are not supported. Memory mapped i/o is not supported. The emulation can be run at maximum speed or limited to a fixed frequency. A timer interrupt can be enabled and used in multiple ways: A timer interrupt after a fixed number of cpu cycles (cc) A timer interrupt with a given frequency when the cpu is running at a fixed speed A timer interrupt with a given frequency when the cpu is running at maximum speed Other interrupt sources are not supported. The non-maskable interrupt NMI is not supported. A timeout for a test can be specified in realtime milliseconds. In and Out access is monitored and must be prepared for. Access to an unprepared address immediately terminates the test. I/o addresses can be prepared in multiple ways: Assign an address to the console (stdin+stdout) provide input data for an In address provide test data for an Out address Not yet supported in zasm v4.4.4 Loading of a rom file read/write/compare to file #### Setting up a test case
    #test <name>, <addr>, <size>
    ;
    .test-clock     <frequency>
    .test-int       <frequency>  [, <duration>]
    .test-int       <cpu_cycles> [, <duration>]
    .test-intack    <int_ack_byte>
    .test-timeout   <duration>
    ;
    .test-in        <addr>, <values>
    .test-out       <addr>, <expected_values>
    .test-console   <addr>
##### .test-clock Define a fixed speed for the emulation. The emulation will be throttled to the given frequency. Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif If `.test-clock` is not specified or Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if the clock is Pseudo instructions: defl, set and '=' Labels: SET set to 0 then the test runs at the fastest possible speed.
    .test-clock 4000000 Hz ; run at 4 MHz.   mind the space!
    .test-clock 3500 kHz   ; run at 3.5 MHz. mind the space!
    .test-clock 6 MHz      ; run at 6 MHz.   mind the space!
##### .test-int Enable a timer interrupt and define the interrupt frequency. The frequency can be given in cpu cycles 'cc' or in real-world frequency. Depending on whether the cpu is running at a fixed speed or unlimited speed the executed cpu cycles per interrupt are predictable or may vary widely.
    .test-int  50 Hz       ; interrupt with real-world frequency
    .test-int  70000 cc    ; interrupt after 70000 cc (50 Hz at 3.5 MHz: the ZX Spectrum :-)
    .test-int  50          ; interrupt with 50 Hz
    .test-int  70000       ; interrupt after 70000 cc
The units cc or Hz are optional. Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif If present, a sanity test is included. Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif If the unit is omitted, zasm uses values up to 1000 as Hz and larger values as cc. 1000 is the highest value which can be used for frequency. Since version 4.0.3 a second argument can be added to specify the duration, for which the interrupt should be asserted. This can be used to test whether interrupts are missed due to longisch sequences with interrupts disabled or whether they interrupt itself, Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if enabled in the interrupt handler too early. It is recommended to use at least 32 cc for the duration, because even Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if your code never disables interrupts (which will easily take longer than that) the longest Command Line Options: --z80 Pseudo instructions: .z80, .z180 and .8080 Targets: #target Z80 Z80 opcodes takes 23 cpu cycles! And, of course, best use the actual duration of your real system. :-) Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif If no interrupt duration is specified, then the interrupt is asserted until it is acknowledged (handled).
    .test-int  50 Hz, 40 cc    ; interrupt with real-world frequency, asserted for 40 cc
    .test-int  70000 cc, 48 cc ; interrupt after 70000 cc, asserted for 48 cc
    .test-int  50, 128         ; interrupt with 50 Hz, asserted for 128 cc
    .test-int  70000, 64 cc    ; interrupt after 70000 cc, asserted for 64 cc
There is one more subtable difference between auto-off mode and int-with-duration mode: In auto-off mode the first interrupt, which would occur at cpu cycle cc = 0 is suppressed. In interrupt-with-duration mode the first interrupt at cc = 0 is not suppressed, and Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if the test code enables interrupts very early, then the first interrupt is immediately taken. ##### .test-intack Define byte to be read from the bus in an interrupt acknowldge cycle. This byte is 0xFF by default (floating bus on a TTL system) but different values can be defined as provided by some peripheral hardware, to supply a `RST` opcode or an index in the interrupt vector table, depending on the current interrupt mode of the cpu.
    .test-intack  255-8            ; this would be a RST 48
    .test-intack  opcode(rst 48)   ; the same, just readable :-)
    .test-intack  lo(int_vector)   ; low byte of memory address of an interrupt vector
                                   ; the high byte would go into the i register.
##### .test-timeout Define a timeout for the test. Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif If the test takes longer it is aborted and fails. The timeout is measured in realtime. Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif If no timeout is Pseudo instructions: defl, set and '=' Labels: SET set or the timeout is Pseudo instructions: defl, set and '=' Labels: SET set to 0 then there is no timeout.
    .test-timeout  1 s     ; timeout after 1 second.        mind the space!
    .test-timeout  500 ms  ; timeout after 500 millisecond. mind the space!
    .test-timeout  1 m     ; timeout after 1 minute.        mind the space!
##### .test-console Attach an i/o address to stdin and stdout. This is an easy way to print messages from the running code. A little more effort must be taken to input text, because the input is not blocking. Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif If no input is available, then the port reads as 0x00.
    .test-console  0xFE    ; use port address 0xFE,   high byte is ignored
    .test-console  0xFFFE  ; use port address 0xFFFE, you must use in(c) and out(c)
##### .test-in Supply input data for an input port. The supplied data is read by inputs from this port. The test fails, Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if the test code reads more data than supplied and it fails Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if there is some unread data left after the test. ###### Basic example
    .test-in  0xF8, 0,0,0,"Hello world!",13,0,0,0
This prepares port 0xF8 to return 3 times 0x00 (probably meaning 'no data'), then a text and finally again 3 times 0x00. All data must be read by the test code.
    .test-in  0xF8, 0,0,0,"Hello world!",13,0,0,0
    .test-in  0xF8, 0,0,0,"Here i go again!",13,0,0,0
This prepares port 0xF8 with more data. The input data is combined from multiple definitions. ###### Repeated data You can repeat blocks of data:
    .test-in  0xF8, {0}*10, "Hello World!", 13, {0}*10
    .test-in  0xF8, {0}*10, {"Hello", 32, "World!", 13} * 5, {0}*10
You can add a final block to repeat forever. This won't make the test fail:
    .test-in  0xF8, {0}*10, "Hello World!", 13, {0}*
##### .test-out Supply output test data for an output port. The supplied data is compared against data written to this port. The test fails, Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if a byte written doesn't match the expectation, Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if the test code writes more data than supplied and it fails Assembler directives: #if, #elif, #else, #endif Pseudo instructions: if, endif if there is some unwritten data left after the test. ###### Basic example
    .test-out  0xF8, "Hello world!",10
This prepares port 0xF8 to Run test code and test your expectations: .expect register Run test code and test your expectations: .expect cc expect a text and a linebreak. All data must be written by the test code.
    .test-out  0xF8, "Hello world!",10
    .test-out  0xF8, "Here i go again!",10
This prepares port 0xF8 with more data. The output test data is combined from multiple definitions. ###### Repeated data You can repeat blocks of data:
    .test-out  0xF8, {'-'}*12, 10, "Hello World!", 10, {'-'}*12, 10
    .test-out  0xF8, {'-'}*12, 10, {"Hello World!", 10} * 5, {'-'}*12, 10
You can add a final block to repeat forever. This won't make the test fail:
    .test-out  0xF8, {"Hello World!",10,}*  ; any number of repetitions of this block
    .test-out  0xF8, "Hello World!", 10, *  ; any data whatever after text
#### Run test code and test your expectations After the test segment is setup, you can add your test code. It starts up with all registers Pseudo instructions: defl, set and '=' Labels: SET set to 0x00 and interrupts disabled. Typically you load some registers and call a function to test. It is recommended to wrap all tests in a Assembler directives: #local, #endlocal, .local and .endlocal Pseudo instructions: #local, #endlocal, .local and .endlocal Including C Source Files: #local, #endlocal, .local and .endlocal#local context so you can reuse Pseudo instructions: Label definition Numeric expressions: Labels 8080 Assembler: Labels label names:
    Assembler directives: #local, #endlocal, .local and .endlocal
    Pseudo instructions: #local, #endlocal, .local and .endlocal
    Including C Source Files: #local, #endlocal, .local and .endlocal#local
        ld  sp,0
        ld  a,3
        ld  de,7
        call A_times_DE
        ;
    .Run test code and test your expectations: .expect register
    Run test code and test your expectations: .expect ccexpect a' = 0
    .Run test code and test your expectations: .expect register
    Run test code and test your expectations: .expect ccexpect a = 3
    .Run test code and test your expectations: .expect register
    Run test code and test your expectations: .expect ccexpect de = 7
    .Run test code and test your expectations: .expect register
    Run test code and test your expectations: .expect ccexpect hl = 3*7
    .Run test code and test your expectations: .expect register
    Run test code and test your expectations: .expect ccexpect dehl = 7*$10000 + 3*7
    .expect cc < 1000
    Assembler directives: #local, #endlocal, .local and .endlocal
    Pseudo instructions: #local, #endlocal, .local and .endlocal
    Including C Source Files: #local, #endlocal, .local and .endlocal#endlocal
##### .expect register .Run test code and test your expectations: .expect register Run test code and test your expectations: .expect cc expect can be used to test register values. You can compare the value of any register, register pair or quad register to match an expected value. Ordered comparisons ('>' or '<') are not allowed. Recognized register names are:
     a f b c d e h l a2 f2 b2 c2 d2 e2 h2 l2 a' f' b' c' d' e' h' l'
    xh xl yh yl ixh ixl iyh iyl pch pcl sph spl i r
    af bc de hl af2 bc2 de2 hl2 af' bc' de' hl' ix iy pc sp
    bcde bchl bcix bciy debc dehl deix deiy etc.
    im iff1 iff2
##### .expect cc .Run test code and test your expectations: .expect register Run test code and test your expectations: .expect cc expect can also test the cpu cycle counter. You can compare the value of the cpu cycle counter to match an expected value or use an ordered comparisons '>' … '<'. The cycle counter is reset after each block of .Run test code and test your expectations: .expect register Run test code and test your expectations: .expect cc expects, either cc or registers.
    .expect cc = 456
    .expect cc >= 400
    .expect cc > 400
    .expect cc <= 500
    .expect cc < 500
#### Tips Hint: assemble your source with Differences from v3 to v4: Command line options Command Line Options Command Line Options: Command line options command line option -uwy to see the generated code and cycle count. Hint: run tests with Differences from v3 to v4: Command line options Command Line Options Command Line Options: Command line options command line option -v to see more interesting output. B-) #### Example files source file listing |

[<prev] [top] [next>]