Unkatris, another tetris clone

Any discussions related to the creation of new hardware or software for the ZX80 or ZX81
sirmorris
Posts: 2811
Joined: Thu May 08, 2008 5:45 pm

Re: Unkatris, another tetris clone

Post by sirmorris »

Excellent work!
User avatar
zsolt
Posts: 203
Joined: Wed Apr 20, 2011 11:43 am
Location: Fót, Hungary

Re: Unkatris, another tetris clone

Post by zsolt »

Cool, congrats!
Is it possible to take a look to your loader part? (the 1st block) - it is very interesting. :o
Regards,
Zsolt

PS: The 1kchess? It was my project for this summer :D , and finally I got similar results
ZX81 (8K), ENTERPRISE 128, [ZX SPECTRUM (48K,+,+128K,+2,+2A), TS1000, TS1500, TS2068, Cambridge Z88, PRIMO A64 (red)]
antoniovillena
Posts: 23
Joined: Fri Aug 15, 2014 5:48 pm

Re: Unkatris, another tetris clone

Post by antoniovillena »

zsolt wrote:Cool, congrats!
Is it possible to take a look to your loader part? (the 1st block) - it is very interesting. :o
Regards,
Zsolt

PS: The 1kchess? It was my project for this summer :D , and finally I got similar results
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.
block1.png
block1.png (14.7 KiB) Viewed 2993 times
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.
David G
Posts: 44
Joined: Thu Jul 17, 2014 7:58 am

Loading System for 1k program

Post by David G »

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.

Code: Select all

1 RAND USR 16393
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.

Code: Select all

100 SAVE "APP"
110 GOTO 1
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

; 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.
antoniovillena
Posts: 23
Joined: Fri Aug 15, 2014 5:48 pm

Re: Unkatris, another tetris clone

Post by antoniovillena »

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.
User avatar
marste
Posts: 145
Joined: Sun Aug 10, 2014 9:58 pm
Location: Italy
Contact:

Template for Make1K.exe

Post by marste »

If I understood properly this should be the template for a generic program, correct?
(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

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?
Last edited by marste on Sun Sep 21, 2014 2:38 am, edited 3 times in total.
User avatar
PokeMon
Posts: 2225
Joined: Sat Sep 17, 2011 6:48 pm

Re: Unkatris, another tetris clone

Post by PokeMon »

marste wrote: - is possible to use LAST_K and DB_ST space if no BASIC keyboard routines are used?
No - it's not possible unless you won't accept keys in your program. ;)
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. :mrgreen:
User avatar
marste
Posts: 145
Joined: Sun Aug 10, 2014 9:58 pm
Location: Italy
Contact:

Re: Unkatris, another tetris clone

Post by marste »

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)
David G
Posts: 44
Joined: Thu Jul 17, 2014 7:58 am

Re: Template for Make1K.exe

Post by David G »

marste wrote:Some clarifications:
- what is the reason for the line "E_LINE defw $4401 ; ld bc, $1c44"?
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.

ld bc, $1c44 is commented out by the semicolon.
David G
Posts: 44
Joined: Thu Jul 17, 2014 7:58 am

Re: Unkatris, another tetris clone

Post by David G »

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:
81_file_open_Multiple_Selection.JPG
81_file_open_Multiple_Selection.JPG (19.97 KiB) Viewed 2918 times
Then disable Flash Load and Auto-Start on Insert
81_tape_manager_options.jpg
81_tape_manager_options.jpg (14.93 KiB) Viewed 2918 times
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:
unkatris_BLOCK1.asm.zip
Single-file for Block Loader
(816 Bytes) Downloaded 109 times
Post Reply