What is it?
The Z80 Programming Competition (from now on refered to as ZPC) is a programming competition where the objective is to write small and/or fast routines (functions) in Z80 assembly. The routine(s) should solve one or more problems, stated in each round. Each round will last for one or more weeks (depending on the nature of the problems) and will contain one to four problems.
What kind of problems will there be?
All problems will be platform independent; the routine should work on all kind of computers and electronical devices with a Z80 processor.
The problems will most of the time be quite simple to solve; the competition is about making the program as small (in bytes) as possible and/or as fast (in T-states) as possible.
Some (short) problem statments could be to write a routine that...
- ...mirrors the bits in a byte (ie, turn 10110100b into 00101101b).
- ...converts a string to uppercase.
- ...sorts a set of 8 bit integers using a specific algorithm.
This is not a beauty contest! If your code looks nice and clean, it's a bad sign! :-)
More details on the rules please!
The following rules are important so please read them carefully!!! Specific problems may override one or more of these rules, but this is mentioned in the problem statement specifically!
INPUT
Except for the parameters passed to the routine, you may not assume that any register holds any specific value when the routine is called. Exceptions are bit 7 in R and bit 0 in SP, which will both be 0.
OUTPUT
The output is in most problems done by setting one (or more) registers to "the answer", or change some part of the memory according to the problem statement. All other registers may be "trashed" by the routine (exception: upon return from the routine, SP should be equal to the value it had when the routine was being called).
MEMORY
Temporary variables may by default not be used (most of the times the registers are enough). However, a lot of problems will allow a certain number of bytes to be used for temporary storage. These temporary bytes will not be counted in the program size.
If temporary memory is allowed, you may assume that the label TEMP equals an address in the memory which is the start of the temporary memory. You can then, in the beginning of the program, define temporary variables like this:
var1 = TEMP
var2 = TEMP+1
SELF-MODIFYING CODE
By default, the program is assumed to lie in the RAM, so it is allowed to modify the code and change opcodes of code to be run in the future. The self-modifying code must not "destroy" the function. That is, the function must be able to execute again (any number of times).
Changes in predefined data (like arrays) follow the same rules as self-modifying data.
Note: If temporary variables are not allowed, you may reserve memory in the code and use this memory as variable storage. This will, of course, make the routine bigger...
LOCATION
The start of the program will be at a random address. Thus you can not assume that the routine will start on, say, an even $100 address. This includes predefined data. You may, however, align predefined data like this: (with TASM syntax)
.org ($+7)&$FFF8
However, this will cost you 7 bytes (worst case).
RESTRICTIONS
You may not use any instructions refering to interrupts: DI, EI, LD A,I, LD I,A, RETI and RETN.
You may not use the shadow registers (instructions EX AF,AF', EXX)
You may not change any part of the memory which is not code or predefined data (self-modifying code) or temporary variables. The only exception to this is the stack, which can be assumed to fit $100 bytes ($80 pushes) unless otherwise specified.
MISCELLANEOUS
You are allowed to use undocumented opcodes. If there are any problems determining the speed the instructions, the instruction will be counted as taking 20 T-states.
The routine should end with a RET (or RET ) instruction.
You may assume that the code is run when interrupts are disabled.
You may use some subroutine in two or more of your problems. However, notice that its size will be counted for each problem, and not only once!
Who is the winner?
Each person submitting a valid solution will get a score. Depending on the round, the score will either be the sum of the sizes of the routines, or the sum of the average number of T-states required by each routine. Please note that you will only get a score if your solution is valid, that is, you must have solved all problems in the round.
You may submit a solution any number of time during the week(s), either to make your solution valid or to improve (optimize it). If your solution is not valid, you will get an e-mail within 24 hours of your submission telling you that your solution is not valid.
The winner is the person with the lowest score (of course...). In the case of a tie (which is likely to happen), the winner will be the one who submitted his/her solution first. So, submit early!!!
How do I submit a solution?
By sending an e-mail to yarin@acc.umu.se with the header SUBMIT. The e-mail should include...
- Your real name
- Your e-mail address
- The source code to all routines
All submitted source code may be published on the competition page after the round has been finished!!
Is there a highscore table I can watch during the competition week?
Yes, you will be able to check how your solution compares to the others during the week, and thus know if you should try to optimize it. Note that you will only be able to see the score of each entry, not the individual routine sizes (or T-states).
The highscore table will be updated as soon as an entry have been verified.
What about the winner?
The winner will be mentioned on this web site, including the trophy with his/her name on it. Furthermore, he/she'll be included in the list of previous winners.
How about an example...?
Below follows an example of a round specification consisting of two (small) problems:
Optimization:
Size
Problem 1:
Write a routine which complements the Zero flag, and preserve the values of all other registers, including all other flags:
Input: | None |
Output: | Zero flag complemented |
Problem 2:
Write a routine which reverses a null-terminated string of any size (<64k):
Input: | HL -> Null-terminated string |
Output: | The string pointed to by HL is reversed (HL may be trashed) |
Spec.: | You may NOT use any temporary storage!!! Since there is no limit of the string size, you can't reserve any memory for it. |
Example e-mail:
Subject: SUBMIT
Name: Jimmy Mårdell
E-mail: yarin@acc.umu.se
Problem 1
---------
push af
ex (sp),hl
ld a,l
xor $40
ld l,a
ex (sp),hl
pop af
ret
Problem 2
---------
push hl
xor a
ld b,a
ld c,a
cpir
dec hl
pop de
Loop:
push hl
or a
sbc hl,de
pop hl
ret z ; Must check for equality twice... carry won't do
dec hl
push hl
or a ; Maybe not necessary
sbc hl,de ; in case of overflow
pop hl
ret z
ld a,(de)
ld b,(hl)
ld (hl),a
ld a,b
ld (de),a
inc de
jr Loop