Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Xeda112358

Pages: [1] 2 3 ... 306
1
ASM / Re: [8X+] flash snacks
« on: June 29, 2019, 01:06:51 pm »
Thanks a bunch, I might think a way to use this! @E37 : there are some pretty decent existing flash-to-RAM routines.
A classic way to increment HL through RAM pages is to do something like:
Code: [Select]
    inc l
    call z,incHLmem1
...
...
incHLmem1:
  inc h
  ret po
  ld h,a
  in a,(6)
  inc a
  out (6),a
  ld a,h
  ld h,40h
  ret
That method averages between 14cc and 15cc and advances the page as needed. You need to initialize by swapping in the correct page, though.

Here is my take on a flash-to-RAM routine, though:
Code: [Select]
FlashToRAM:
;Inputs: Same as LDIR, but A is the page number.
;Outputs:
;    Same as LDIR, except A is the ending page.
;
;Speed:
;RAM: 21+21n
;ARC, but no boundary: 114+21n
;Arc, on two pages: 21n+269
;Arc, on three pages: 21n+355
  or a
  jp z,ReadRAM
  out (6),a
  add hl,bc
;  jr c,read_from_Arc_blocks   ;if you need this, you probably need a different routine. This implies that writing will eventually reach the 0x0000 to 0x3FFF range.
  jp p,read_from_ARC_noboundary
read_from_Arc_blocks:
;If we make it here, we know that we cross a page boundary (or in one case, we just reach it and need to return on the next page).
;We will read in blocks to avoid checking page boundaries
;To do so, we first read up to 0x8000 - HL bytes
  xor a
  sbc hl,bc
  sub l \ ld l,a
  ld a,$80 \ sbc a,h \ ld h,a
  ;now we will subtract BC-HL  -> BC
  ld a,c \ sub l \ ld c,a
  ld a,b \ sbc a,h \ ld b,a
  push bc
  ld b,h
  ld c,l
  xor a \ sub l \ ld l,a
  ld a,$80 \ sbc a,h \ ld h,a
  ;now we read the first block
block_loop:
  ldir
  ;now we increment the page and continue reading from $4000
  in a,(6)
  inc a
  out (6),a
  ld h,40h
  pop bc
  ;if BC<$4000, just LDIR the rest
  ld a,b
  sub h
  jr c,read_from_RAM
  ld b,a
  push bc
  ld b,h
  ld c,l
  jp block_loop
read_from_ARC_noboundary:
;  or a     ;already reset
  sbc hl,bc
read_from_RAM:
  ldir
  in a,(6)
  ld b,a
page_restore = $+1
  ld a,0
  out (6),a
  ld a,b
  ld b,c
  ret
ReadRAM:
  ldir
  ret
It needs to run in RAM and uses SMC.

2
ASM / Re: Using APD in your program
« on: June 27, 2019, 08:41:02 pm »
This is clever, nice work!

3
TI Z80 / Re: YATE - Yet Another Tilemap Engine
« on: June 03, 2019, 12:34:45 am »
Just a minor update: I'm working on making a tilemap editor in Python. It isn't great, but it will hopefully make development easier. I figured that I'd upload my progress here in case someone wants to modify it.

You need to have a "tiles.png", but otherwise you can run tilemap.py to start editing the map and tiles. This program requires pygame and uses Python 2 (not 3 :( ).

Layout:
The left-side 800x800 part of the screen is the tilemap.
The middle 512x800 is the tileset. (actually 512x512 is used)
The right-side is a tile editor

Controls:
Click on a tile and that loads it as the current tile to draw with or edit. Click or click-and-drag on the map area to draw the tile, or on the tile editing area to toggle the pixel. Press the 's' key to save, or the 'l' to load a new map (prompt is in the commandline!).




4
TI Z80 / Re: YATE - Yet Another Tilemap Engine
« on: May 29, 2019, 06:45:47 pm »
Updates!

I now have saving working. Currently the save file is allotted 350 bytes. Whether or not it is archived, it gets copied to a temporary file in RAM. When you exit, the new data is automatically written back to the main save file. In the future, I want this to be a toggleable feature.

I also added in dialog boxes! This was tough to code. Due to the strange screen buffer format, I had to write text and rectangle routines from scratch.

I extended the abilities of the scripting language. Now it can initiate dialog boxes, read or write flags and tiles, and a few other things, probably.

I have now added in two more kinds of events-- one for when the user selects a tile (presses [Enter] to pick up an item or talk to someone, for example), and another for when the map is being loaded. In the example screenshot that I'll post below, map 0 checks two flags to determine if it should erase the flower tile upon loading. map 1 will warp the player out of that map until they've completed the task of bringing a flower.

I've included some defines to facilitate writing scripts in "parse.inc". You can view the (uncompressed) map files for example usage. For example, the map1 event code:
Code: [Select]
;events
.dw onload-$-1
.dw onselect-$-1
;if (y == 4 or y == 5) and x == 7:
;    warp(0,2,5)
.db "y"
num(4)
.db "-"
num(2)
.db "<x"
num(7)
.db "=&i"
warp(0,2,5)
.db 0

onload:
  ifnflag(0)
  jump(getout)
  ;else if flag 0 and flag 1 are set, need to do fancy stuff
  ifnflag(1)
  .db 0
  resflag(1)
  dialog(d_1)
  .db 0
getout:
  setflag(1)
  dialog(d_0)
  warp(0,2,5)
  .db 0

onselect:
  .db 0

d_0:
  .db "Get out stinky child!",c_nl
  .db "Don't come back",c_nl
  .db "without a floral",c_nl
  .db "aroma!",0

d_1:
  .db "Oh! What a lovely",c_nl
  .db "aroma! Please come in!",0

Finally, I added a tool to convert from Pixelscape's tilemap format to the format used here. Just run conv.py, passing the input file name on the commandline.

Here is the screenshot:

For some reason, Chrome renders the last dialog of the gif at the wrong speed.

5
TI Z80 / Re: YATE - Yet Another Tilemap Engine
« on: May 28, 2019, 08:16:32 am »
You'd basically have to write it from scratch, but the general idea isn't too complicated to port.

6
TI Z80 / YATE - Yet Another Tilemap Engine
« on: May 27, 2019, 09:58:09 pm »
Hi all! At Eeems' suggestion, I am posting this work-in-progress code :P

I've been working on-and-off on my tilemap engine since my Pokemon Amber attempt. The current rewrite is slower, but a bit easier to work with on the my end. It also allows the surrounding map to still be animated if I need to pull up a menu or dialog! I've also added in map compression using modified code from my LZD project, as well as event tiles!

In this version, I mess around with OS RAM to make larger chunks of contiguous non-user RAM, so it might cause crashes.

As of now, all you can do is walk around the map and enter/exit map editing mode. Since maps are currently stored in the app, map editing is not permanent. If you leave the map and come back, all changes are reverted.

If you want to edit the map:
Code: [Select]
Press [mode] to enter map editing mode
Use [+] and [-] to scroll through the available tiles for the map
Use [*] to toggle walkability. You'll see corner guards if the tile can't be walked on.
Use [Enter] to set a tile.
Use [stat] to exit map editing

When you hover over a tile that can't be walked over, a solid border will be drawn.
When you walk over an event tile, a dotted border will be drawn.


If you want to *actually* edit or create maps, you'll have to do that on your computer and recompile the app. You'll need spasm (with app signing enabled!) and Python with numpy. The map structure is:
Code: [Select]
.db height,width
 .db start_y,start_x   ;The player will be drawn at y+5 and x+6 !
 .db number_of_tiles
 .dw tile_index_0
 .dw tile_index_1
 ...

;map data
 .db blah
 .db blah
 .db blah
...

;Event code
 .db 0
The map data is actually stored transposed. So the tiles you see across the top row are actually stored in the left column of bytes! This makes it a headache to code.

You can use up to 64 different tiles in a map.

Each byte in the map has the index into the tileset stored in the lower six bits. Setting  the top bit means it can't be walked on, and setting bit 6 means walking into it triggers an event.

When events are triggered, the map's event handler is parsed an executed. It is a very basic scripting language that currently handles addition, subtraction, =, <, &, warping, and conditional execution. Scripts end with a null byte (0x00) and are stored similarly to how they'd be parsed in RPN format, currently with the exception of conditional execution (since the condition is checked before executing). 'x' and 'y' can be used to read the player's current coordinates, 'i' evaluates a condition (like an If statement) and if it is true, it executes the next command, otherwise it skips. 'w' is used to warp and requires bytes in the form of `map_id,start_y-5,start_x-6`. Finally, 8-bit integers are prefixed by a `.db 1`. For a convoluted example, here is the event handler for inside the "house" :
Code: [Select]
;if (y == 3 or y == 4) and x == 7:
;    warp(0,2-5,5-6)
.db "y",_num,3,"-",_num,2,"<x",_num,7,"=&iw",0,2-5,5-6
.db 0


Once you've made your map, you'll need to compress it. First you'll compile it to a binary, then you need to compress that data and convert the compressed data back to assembly. For example:
Code: [Select]
spasm maps/map9.z80 maps/map9.bin
python zlz.py maps/map9.bin maps/map9_comp.z80 map9

And finally, you need to add the map to the mapLUT found near the bottom of main.z80, just add the label name (in the above case, `.dw map9`) and include the compressed version of the file at the bottom.



The system is largely interrupt-based. A custom interrupt updates the current keypress, updates the tile animation, updates the LCD, and draws the tilemap. All you have to do is set the appropriate flag:
Code: [Select]
rpgflags  = 33
updateLCD = 0   ;Tells the interrupts to update the LCD
drawmap   = 1   ;Tells the interrupts to redraw the map
animate   = 2   ;Tells the interrupts to animate tiles
noupdate  = 3   ;Overrides the interrupt's LCD update and tilemap redraw
When a tile's animation counter runs out, it automatically sets the drawmap flag. When a map is redrawn, it automatically set the updateLCD flag and resets the drawmap flag (no need to keep doing it). And if the noupdate flag is set, then interrupt-based map drawing and LCD updating is disabled (but these can still be used manually).

There are three graphics buffers, one of which is quite non-standard. They are all vertically aligned instead of horizontally aligned (the OS' format is horizontal). That means the second byte corresponds to the 8-pixel chunk below the first byte, as opposed to adjacent to it.
Code: [Select]
gbuf     : This is a 1120-byte buffer! It is 80 pixels tall and 112 pixels wide. Only the center part is shown. This is where the tiemap is drawn.
maskbuf : A 768 byte buffer. During LCD updates, the data here is ANDed on top of the gbuf data.
topbuf  : A 768 byte buffer. During LCD updates, the data here is ORed on top of the previous data.

The latter two buffers are used for overworld graphics, like the player sprite, or in the future, dialog, menus, and NPCs, etc.

7
Introduce Yourself! / Re: Greetingz
« on: May 09, 2019, 08:53:54 pm »
Hi, welcome to Omni! It is customary to give newcomers !peanuts

What's your Discord name?

8
While I don't know of a solution for any calc, what calculator is this for?

9
ASM / Re: Miscellaneous ASM Questions
« on: April 25, 2019, 06:34:33 pm »
Oh, good point, I was still stuck on translating the tau tokens at parse time.

I wasn't intending to come off as sarcastic, I just went from point A to C without sharing point B, so to speak. I was thinking context hooks and whatnot, but the hooks I listed are easier to work with. "Only" those hooks seemed like a way easier task to me :P

Your idea(s) are legitimately really clever and I just got really excited when I read it (how I feel whenever I see a really clever implementation or optimization).

10
Other / Re: Variables in TI-84 Plus Ce
« on: April 25, 2019, 08:57:20 am »
That requires a Computer Algebra System (CAS). I don't have that calc, so I am not aware of any CAS or symbolic manipulation programs for it.

11
TI Z80 / Re: Unnamed Optimizing Compiler
« on: April 24, 2019, 01:28:08 pm »
I put it up on GitHub. I added the GotoIf() function, which is really important for a programming language. From this, I'll build blocks like If, While, For, etc.
Here is input code:
Code: [Select]
4->k
0->x
1->y
lbl0:
  x+y->z
  x+1->x
  y+1->y
  Disp(10*z)
  k-1->k
  GotoIf(lbl0,k!=0)
2->x
Disp(x)
And attached is a screenshot of what the program displays.
As cool as that is, the generated assembly code is pretty ugly:
Code: [Select]
#include "jq.inc"
#include "ti83plus.inc"
scrap           = 8000h
var_k           = scrap+0
var_x           = scrap+2
var_y           = scrap+4
var_z           = scrap+6
.db $BB,$6D
.org $9D95
 ld hl,4
 ld (var_k),hl
 ld hl,0
 ld (var_x),hl
 ld hl,1
 ld (var_y),hl
lbl0:
 ld hl,(var_x)
 ld de,(var_y)
 add hl,de
 ld (var_z),hl
 ld hl,(var_x)
 inc hl
 ld (var_x),hl
 ld hl,(var_y)
 inc hl
 ld (var_y),hl
 ld hl,(var_z)
 add hl,hl
 add hl,hl
 ld de,(var_z)
 add hl,de
 add hl,hl
 call disp_uint16
 ld hl,(var_k)
 dec hl
 ld (var_k),hl
 ld a,h
 or l
 jqnz(lbl0 )
 ld hl,2
 ld (var_x),hl
#include "disp_uint16.z80"

12
TI Z80 / Re: HYBRID (8X+)
« on: April 24, 2019, 08:39:44 am »
Oh, great news! I've had a few big projects like that (lost and then years later found a place that had an earlier backup). Good luck; it's a lot of work trying to relearn your old code.

13
ASM / Re: Miscellaneous ASM Questions
« on: April 23, 2019, 02:10:19 pm »
Holy heck that is clever! So all you'd need a token hook, RawKeyHook, and parser hook.

14
TI Z80 / Re: Unnamed Optimizing Compiler
« on: April 23, 2019, 11:23:08 am »
I finally compiled a real program!

With this new iteration of the program, I am using an AST to perform algorithmic optimizations, but I am compiling with a modified version of the original method. Now it is producing better code that is (importantly) correct. My first attempt with this version got really, really slow on slightly complicated inputs-- I terminated the process after two hours trying to compile one line (it wasn't an infinite loop, either; the search space got huge).

So I modified it to allow limiting the amount of paths it kept in memory Keeping a single path would produce code like the previous version, but I found that 60-100 would produce decent code, while 200 produces better code.

It *still* doesn't track state, so there are lots of unnecessary ld hl,() and whatnot.

Anyways, here is what compiling via the commandline might look like:
Code: [Select]
#Convert the code to an intermediate representation
python sy.py test.txt

#Convert the intermediate representation to Z80 assembly, with the ti-83+ family header
python compile.py test.ir -TI8X -MAX_PATHS=150

#Compile
spasm test.asm bin/test.8xp -I inc -I routines

It will take a few seconds to generate the assembly, but it works! Attached is a screenshot of the following code:
Code: [Select]
3->x
6->y
Disp(3*(2*x+y*3)+9*(x+y))
Disp(1337)
Disp(3*(x+y)+9*(x+y))

15
ASM / Re: Miscellaneous ASM Questions
« on: April 22, 2019, 09:34:37 pm »
I'm fairly sure that the parser hook doesn't let you intercept non-function tokens. I could be wrong about that, but I don't think so.

Pages: [1] 2 3 ... 306