Unkatris, another tetris clone
Re: Unkatris, another tetris clone
Excellent work!
Re: Unkatris, another tetris clone
Cool, congrats!
Is it possible to take a look to your loader part? (the 1st block) - it is very interesting.
Regards,
Zsolt
PS: The 1kchess? It was my project for this summer , and finally I got similar results
Is it possible to take a look to your loader part? (the 1st block) - it is very interesting.
Regards,
Zsolt
PS: The 1kchess? It was my project for this summer , and finally I got similar results
ZX81 (8K), ENTERPRISE 128, [ZX SPECTRUM (48K,+,+128K,+2,+2A), TS1000, TS1500, TS2068, Cambridge Z88, PRIMO A64 (red)]
-
- Posts: 23
- Joined: Fri Aug 15, 2014 5:48 pm
Re: Unkatris, another tetris clone
The first block is very simple. I have deleted the source that generates the arrays in make1k.c, but here you have an image to clarify.zsolt wrote:Cool, congrats!
Is it possible to take a look to your loader part? (the 1st block) - it is very interesting.
Regards,
Zsolt
PS: The 1kchess? It was my project for this summer , and finally I got similar results
Of course all the process is automatic. You only have to create a 1024 bytes file binary and parse that binary to the tool make1k. After the parse you'll have .z81, .tzx and .wav files that loads all the 1024 bytes into the RAM.
Loading System for 1k program
The loader is ingenious. I see no way to generate it on the ZX81, at least not from the Basic environment. But if you create it using special tools, it will load, then auto-run this statement which will load the next block.
The System Variable NXTLIN contains the address of the BASIC line to auto-run. And it is saved to tape. Normally it is pointing to the end of a line when you save a tape (will not auto-run), but will be a valid address if you save from a running program.
After saving this program, load it from tape, and the ZX81 will automatically start running the program at line 110.
That is the basic idea, though BLOCK1.p works slightly different. It only has one BASIC line and some machine code.
File: (UNKATRIS_4) BLOCK1.P Size: 65 bytes (41h bytes)
ADDR 0 1 2 3 4 5 6 7 8 9 A B C D E F
4009 31 FE 43 21 40 40 1E 00-43 18 0D 49 40 00 00 00 (address 16393) machine code
4019 00 00 00 00 00 00 00 00-ED B0 18 06 00 00 00 00
4029 2E 40 C3 40 03 00 01 00-00 F9 D4 25 25 7E 8F 00 1 RAND USR 16393
4039 12 76 76 0B 0B 76 76 00-80 00 00 3A 26 40 3C 28
4049 00
See ZX81 Basic Programming Appendix A - The Character Set and "Chapter 27 - Organization of Memory".
Memory location 4009h (16393) is normally where VERSN is stored, but in this loader Antonio is storing user code there. It is the first memory location saved to tape. There are a few System Variables needed to run the standard display, but several gaps between these "required" system variables. Machine code can be copied there. Antonio has perfected this idea with his machine code loading system, thereby freeing up a hundred or so bytes on a 1k system.
Code: Select all
1 RAND USR 16393
Code: Select all
100 SAVE "APP"
110 GOTO 1
That is the basic idea, though BLOCK1.p works slightly different. It only has one BASIC line and some machine code.
File: (UNKATRIS_4) BLOCK1.P Size: 65 bytes (41h bytes)
ADDR 0 1 2 3 4 5 6 7 8 9 A B C D E F
4009 31 FE 43 21 40 40 1E 00-43 18 0D 49 40 00 00 00 (address 16393) machine code
4019 00 00 00 00 00 00 00 00-ED B0 18 06 00 00 00 00
4029 2E 40 C3 40 03 00 01 00-00 F9 D4 25 25 7E 8F 00 1 RAND USR 16393
4039 12 76 76 0B 0B 76 76 00-80 00 00 3A 26 40 3C 28
4049 00
See ZX81 Basic Programming Appendix A - The Character Set and "Chapter 27 - Organization of Memory".
Memory location 4009h (16393) is normally where VERSN is stored, but in this loader Antonio is storing user code there. It is the first memory location saved to tape. There are a few System Variables needed to run the standard display, but several gaps between these "required" system variables. Machine code can be copied there. Antonio has perfected this idea with his machine code loading system, thereby freeing up a hundred or so bytes on a 1k system.
Code: Select all
; Disassembly of the file BLOCK1.P;
4009 VERSN 31fe43 ld sp,$43fe ; normalize STACK pointer to 43FEh (2 less than 4000 + 1k)
FLAGS EQU VERSN+1 ; Bit 7 of FLAGS must be set to allow the execution of a BASIC line
400c D_FILE 214040 ld hl,$4040 ; Code to be moved
400f 1e00 ld e,$00 ; DE is 4049h after USR start. DE is now 4000h
4011 43 ld b,e ; BC is 4009h after USR 4009h. BC is now 0009
4012 180d jr SPARE1 ; $4021 (+$0d)
4014 db 49
4015 db 40
4016 00 nop
4017 00 nop
4018 00 nop
4019 00 nop
401a 00 nop
401b 00 nop
401c 00 nop
401d 00 nop
401e 00 nop
401f 00 nop
4020 00 nop
4021 SPARE1 edb0 ldir ; move BC (9) bytes from HL (4040h) to DE (4000h)
4023 S_TOP 1806 jr OLDPPC ; $402b (+$06)
4025 00 nop
4026 00 nop
4027 00 nop
4028 00 nop
4029 NXTLIN 2e40 dw 402Eh ; After loading from tape, start executing the BASIC statement at the specified address
402b OLDPPC c34003 jp 0340h ; "LOAD" ROM subroutine
402e 0001 defw 0001 ; BASIC line number 1
4030 0000 defw 0000 ; length of BASIC line (only critical if LISTing or if the line finishes)
4032 db f9 ; RAND token
4033 db d4 ; USR token
4034 FRAMES db 2525 ; "99" (abitrary? display number)
4036 db 7e ; floating point marker
4037 db 8f00127676 ; Floating point: 16393 (the actual number)
403c 0b0b dbzx '""' ; two quotes ""
403e db 76 ; End Of Line marker
403f db 76
4040 defs 9 ;first 9 bytes of the game are located here, to be moved by the loader to 4000h
4049 db 28h
404a db 0
Last edited by David G on Wed Sep 17, 2014 11:29 pm, edited 1 time in total.
-
- Posts: 23
- Joined: Fri Aug 15, 2014 5:48 pm
Re: Unkatris, another tetris clone
You explained perfectly the loader. The "99" display number is because there is the FRAMES variable and is decremented, but now I think that a simple "9" also works. The last $28 belongs to the 9 bytes of the game.
And the most important, the SP at $43FE will point 2 bytes below the top of the memory. These two bytes are used later in the 2nd block to store the pointer to the first C/M instruction to execute. In the 2nd block there is no BASIC loader, we leave the ROM Basic routine via RET (in the ROM) with SP pointing to $43FE. This method lets you fill the entire RAM for your game, with some restrictions as the gaps in system variable area but if you resolve it well you can exploit almost the 1024 bytes of RAM.
And the most important, the SP at $43FE will point 2 bytes below the top of the memory. These two bytes are used later in the 2nd block to store the pointer to the first C/M instruction to execute. In the 2nd block there is no BASIC loader, we leave the ROM Basic routine via RET (in the ROM) with SP pointing to $43FE. This method lets you fill the entire RAM for your game, with some restrictions as the gaps in system variable area but if you resolve it well you can exploit almost the 1024 bytes of RAM.
Template for Make1K.exe
If I understood properly this should be the template for a generic program, correct?
(tested and something should be still not ok...)
Some clarifications:
- what is the reason for the line "E_LINE defw $4401 ; ld bc, $1c44"?
- is possible to use LAST_K and DB_ST space if no BASIC keyboard routines are used?
(tested and something should be still not ok...)
Code: Select all
; to be compiled with sjasmplus.exe
output file.bin ; to be then converted with make1k.exe by Antonio Villena
org $4000
block 12,0 ; free space
D_FILE defw _dfile
block 6,0 ; free space
E_LINE defw $4401 ; ld bc, $1c44
block 15,0 ; free space
LAST_K defw $ffff
DB_ST defb 0
MARGIN defb 55
block 11,0 ; free space
FRAMES defw 0
_start ; program starting point
block $4300-$,0 ; free space
_dfile block 25,$76 ; video memory
block $43fe-$,$76 ; free space
defw _start ; starting point: SP will be put here and ret performed
- what is the reason for the line "E_LINE defw $4401 ; ld bc, $1c44"?
- is possible to use LAST_K and DB_ST space if no BASIC keyboard routines are used?
Last edited by marste on Sun Sep 21, 2014 2:38 am, edited 3 times in total.
Re: Unkatris, another tetris clone
No - it's not possible unless you won't accept keys in your program.marste wrote: - is possible to use LAST_K and DB_ST space if no BASIC keyboard routines are used?
The display routine will use both variables and check for keypress every 20ms and overwrite your data.
By the way - the demo file I sent you last time was not good tested from me, it worked with nearly no stack but forgot that I tested it in EightyOne while testing it with 16k memory. So I think you need at least a stack of about 50-60 bytes when loading with BASIC.
The problem of antonios loader is, that you won't receive a .p file which can be loaded by a 1k Zeddy. So in my eyes it doesn't make too much sense to program a very special file which could not be loaded easily from all users. Just my opinion - up to you of course. Programming in 1k is a challenge and programming in 900 bytes would be even better.
Re: Unkatris, another tetris clone
I didn't still test, but seems that Antonio's work is possible to be loaded on a real 1K ZX81!...
If so Unkatris was a superb way to execute the challenge!!!
(and then if some emulator does not load it it is an emulator problem, nothing else)
If so Unkatris was a superb way to execute the challenge!!!
(and then if some emulator does not load it it is an emulator problem, nothing else)
Re: Template for Make1K.exe
E_LINE defw $4401 is creating two bytes ($44 and $01) at that point in the code. And giving it the lable "E_LINE". The assembly is building up the beginning portion of the ZX81 program.marste wrote:Some clarifications:
- what is the reason for the line "E_LINE defw $4401 ; ld bc, $1c44"?
ld bc, $1c44 is commented out by the semicolon.
Re: Unkatris, another tetris clone
This two-part loader is not quite as easy to use with an emulator, but it can be done
* With a real ZX81, just load Block1.p and when ready, load Block2.p. Putting them on tape one after another is the easy way
* With the emulator, the tricks are to disable fast loaders, and get both programs queued up at the same time
With Eighty-One, you may open two files at the same time: Then disable Flash Load and Auto-Start on Insert Finally, after entering LOAD "", select Block1.p and click the Play button
It will automatically load Block1, then Block1 will load Block2
First I opened Antonio's TZX file, which contained
* Program "4" size 66
* Program "4" size 1017
From there I deleted the small program, and saved the large program as Block2.P
Block1.p I created in ZX-IDE from this assembly language file:
* With a real ZX81, just load Block1.p and when ready, load Block2.p. Putting them on tape one after another is the easy way
* With the emulator, the tricks are to disable fast loaders, and get both programs queued up at the same time
With Eighty-One, you may open two files at the same time: Then disable Flash Load and Auto-Start on Insert Finally, after entering LOAD "", select Block1.p and click the Play button
It will automatically load Block1, then Block1 will load Block2
First I opened Antonio's TZX file, which contained
* Program "4" size 66
* Program "4" size 1017
From there I deleted the small program, and saved the large program as Block2.P
Block1.p I created in ZX-IDE from this assembly language file: