Author Topic: Jade  (Read 20895 times)

0 Members and 4 Guests are viewing this topic.

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Jade
« Reply #15 on: March 02, 2013, 07:47:17 am »
Ooh, maybe I will have time today to continue with the assembly version. It actually reads the code in compressed hex form and parses it that way, so if I do not make an editor, it might be a pain to program. Another neat application of this project that I thought about was to create a different CPU and port system with only 256 bytes to work with in all and an even more simple instruction set. Because it cannot damage the calculator, you can fill the code with random data and see what happens. The ports could be for returning how close the nearest pixel is in a given direction and for incrementing an X and Y coordinate. Because it is 256 bytes, you can fit a good number of CPUs in RAM and you can make them all run in parallel and see if they interact on screen. We could set some conditions for survival, death, and procreation, and see if they create anything semi-intelligent :)

Offline TIfanx1999

  • ಠ_ಠ ( ͡° ͜ʖ ͡°)
  • CoT Emeritus
  • LV13 Extreme Addict (Next: 9001)
  • *
  • Posts: 6173
  • Rating: +191/-9
    • View Profile
Re: Jade
« Reply #16 on: March 02, 2013, 09:19:40 am »
That sounds like a game builderboy was describing once. IIRC he ported it to axe (from PC maybe???). I can't recall the name of it at the moment. :/

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Jade
« Reply #17 on: March 02, 2013, 09:28:23 am »
Haha, that does sound like something he would do o.o It is like a complicated cellular automata. Actually, if I do figure out something that works, I might have to use this for a talk that I should be giving about the subject.

As an update, I am about to run the code through ORG to see how many mistakes I have made with it. If no mistakes have been made, then I have completed the assembly version emulating the instruction set and I will need to add in ports (which should be rather trivial).

Offline TIfanx1999

  • ಠ_ಠ ( ͡° ͜ʖ ͡°)
  • CoT Emeritus
  • LV13 Extreme Addict (Next: 9001)
  • *
  • Posts: 6173
  • Rating: +191/-9
    • View Profile
Re: Jade
« Reply #18 on: March 02, 2013, 09:45:44 am »
<a href=http://ourl.ca/15370/288050>Here's</a> Builderboy's game that I was talking about.

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Jade
« Reply #19 on: March 02, 2013, 10:33:26 am »
That looks awesome and is definitely pretty close to what I was talking about. I was more going for what genetic algorithms are, I think. So basically, the computer tries out different types of code to achieve a task and the 'organisms' interact with each other using their 'genetic' code. With the idea that the best suited for the task will survive, you should eventually get a fairly well coded routine for your task. I think this process has been proposed for creating quantum algorithms.

Also, finally some content! I haven't added in any of the ports, so you cannot exit Jade yet and you cannot see what is going on with the sprites, but the instructions appear to be working. There could be issues I haven't caught yet, but the source code is below. It is currently pretty ugly and not very optimised, but I will worry about that later. If you use the code from the previous routine, it will do what it is supposed to do, too. (Set up the keymask port and spritemask port and then set up the first two sets of sprite ports, then enter an infinite loop).

As a note, I haven't documented the hex codes for all of the jumps and calls yet.
Spoiler For Source:

#include    "ti83plus.inc"
#include    "Jade.inc"
#define     progStart   $9D95
.org        progStart-2
.db         $BB,$6D
     bcall(_RclAns)
     sub 4
     ret nz
     ex de,hl
     ld c,(hl)
     inc hl
     ld b,(hl)
     inc hl
     ld de,OP1
     ldir
     ld (de),a
     bcall(_ChkFindSym)
     ret c
     ld ix,saveSScreen
     ld bc,0
     ld hl,saveSScreen
     ld (hl),c
     inc hl
     djnz $-2
     ex de,hl
     ld b,2
     inc hl
     inc hl
     ldir
;now all of the ports and RAM are loaded
     ld ix,saveSScreen+128
MainLoop:
     ld hl,MainLoop
     push hl
     call GetInc
     ld a,%00100000
     and c
     jp z,CMD0
CMD1:
     bit 4,c
     push bc
     push af
     call GetInc
     pop af
     ld d,0
     jr nz,$+8
       ld e,c
       ld hl,saveSScreen
       add hl,de
       ld c,(hl)
     ld e,c
     pop bc
     ld a,15
     and c
     jr z,callf+3          ;jrf
     dec a
     jr nz,$+6             ;jrf c
       bit 0,b
       jr nz,callf+3
     dec a
     jr nz,$+6             ;jrf z
       bit 1,b
       jr nz,callf+3

     dec a
     jr z,callb+3          ;jrb
     dec a
     jr nz,$+6             ;jrb c
       bit 0,b
       jr nz,callb+3
     dec a
     jr nz,$+6             ;jrb 1
       bit 1,b
       jr nz,callb+3

;calls

     dec a
     jr nz,$+8             ;callf
callf:
       call PushPC
       add hl,de
       jr SetPC
     dec a
     jr nz,$+6             ;callf c
       bit 0,b
       jr nz,callf
     dec a
     jr nz,$+6             ;callf 1
       bit 1,b
       jr nz,callf


     dec a
     jr nz,is_callbc             ;callb
callb:
       call PushPC
       or a
       sbc hl,de
SetPC:
     ld a,h
     and 1
     ld h,a
     ld a,(PClow+1)
     and $FE
     or h
     ld h,a
     ld (PClow),hl
     ret
is_callbc:
     dec a
     jr nz,$+6             ;callb c
       bit 0,b
       jr nz,callb
     dec a
     ret nz            ;callb 1
       bit 1,b
       jr nz,callb

PushPC:
     ex de,hl
     push hl
;DE is the value to push
     call PushByte
     ld a,e
     ld e,d
     ld d,a
     call PushByte
     ld h,e
     ld l,d
     pop de
     ret
PushByte:
;E is the value to push
     ld a,(stackptr)
     push af
     and 7Fh
     ld hl,stackbase
     add a,l
     ld l,a
     jr nz,$+3
     inc h
     ld (hl),e
     pop af
     inc a
     ld (stackptr),a
     ret
;DE is offset
;HL = PC
    




CMD0:
     ld a,c
     cp 12
     jr nz,CheckRetC
PopPC:
     call PopByte
     ld d,e
     call PopByte
     ld a,(PClow+1)
     and $FE
     or h
     ld h,a
     ld (PClow),hl
     ret
PopByte:
     ld a,(stackptr)
     dec a
     and 7Fh
     ld (stackPtr),a
     ld hl,stackbase
     add a,l
     ld l,a
     jr nz,$+3
     inc h
     ld e,(hl)
     ret
CheckRetC:
     cp 13
     jr nz,$+7
       bit 0,b
       jr nz,PopPC
       ret
     cp 14
     jr nz,$+7
       bit 1,b
       jr nz,PopPC
       ret
     push af
     call GetInc
     ld a,c
     ld hl,saveSScreen
     add a,l
     ld l,a
     jr nc,$+3
     inc h
     pop af
     push af
     push hl
     and 15
     ld hl,MathLUT
     add a,a
     add a,l
     ld l,a
     jr nc,$+3
     inc h
     ld e,(hl)
     inc hl
     ld d,(hl)
     pop hl
     ex de,hl
     pop af
;A has the main instruction
;DE points to the byte that the operation is on
;     call JPHL
;     jp MainLoop
JPHL:
     jp (hl)
instrLD:
     call GetNumOrAddr
     ld (hl),a
     ret
instrADD:
     call GetNumOrAddr
     add a,(hl)
SetFlags:
     ld (hl),a
     ld b,0
     jr nz,$+4
       inc b
       inc b
     ret nc
     inc b
     ret
instrADC:
     call GetNumOrAddr
     rrc b
     rlc b
     adc a,(hl)
     jr SetFlags
instrSUB:
     call GetNumOrAddr
     neg
     add a,(hl)
     ccf
     jr SetFlags
instrSBC:
     call GetNumOrAddr
     neg
     rrc b
     rlc b
     adc a,(hl)
     ccf
     jr SetFlags
instrXOR:
     call GetNumOrAddr
     xor (hl)
     jr SetFlags
instrOR:
     call GetNumOrAddr
     or (hl)
     jr SetFlags
instrAND:
     call GetNumOrAddr
     and (hl)
     jr SetFlags
instrCP:
     call GetNumOrAddr
     cp (hl)
     jr SetFlags
instrINC:
     bit 4,a
     jr z,$+5
       dec (hl)
       jr SetFlags
     inc (hl)
     jr SetFlags
instrPUSH:
     ld e,a
     jp PushByte
instrPOP:
     push de
     call PopByte
     pop hl
     ld (hl),e
     ret
instrRET:
instrLDIR:
     cp 31
     jr z,$+5
       ld a,(de)
       jr $+7
     ld a,saveSScreen     ;LSB->A
     sub e
     neg
     ld l,a
     ld h,0
     dec l
     push bc
     push hl
     call GetInc
;C is the size of the data
     ld b,c
LDIRLoop:
       call GetInc
       pop hl
       inc l
       push hl
       ld de,saveSScreen
       add hl,de
       ld (hl),c
       djnz LDIRLoop
     pop bc
     pop bc
     ret

;B always contains the flags
GetNumOrAddr:
;HL is what DE was input as
;Returns A as the value
     push de
     push af
     call GetInc
     pop af
     pop hl
     bit 4,a
     ld a,c
     ret nz
     ex de,hl
     ld hl,saveSScreen
     add a,l
     ld l,a
     jr nc,$+3
     inc h
     ld a,(hl)
     ex de,hl
     ret
MathLUT:
     .dw instrLD
     .dw instrADD
     .dw instrADC
     .dw instrSUB
     .dw instrSBC
     .dw instrXOR
     .dw instrOR
     .dw instrAND
     .dw instrCP
     .dw instrINC
     .dw instrPUSH
     .dw instrPOP
     .dw instrRET
     .dw instrRET
     .dw instrRET
     .dw instrLDIR

GetInc:
;Outputs:
;     C as the next byte
;     PC incremented
;     HL = PC
     ld de,(PClow)
     ld a,d
     ld c,d
     and 1
     ld d,a
     ld hl,saveSScreen+256
     add hl,de
     res 0,c
     inc e
     jr nz,$+3
     inc c
     ld d,c
     ld c,(hl)
     ex de,hl
     ld (PClow),hl
     ret
Spoiler For Jade.inc:

;ports
sLSB0     equ 00h
sMSB0     equ 01h
sX0       equ 02h
sY0       equ 03h
sLSB1     equ 04h
sMSB1     equ 05h
sX1       equ 06h
sY1       equ 07h
sLSB2     equ 08h
sMSB2     equ 09h
sX2       equ 0Ah
sY2       equ 0Bh
sLSB3     equ 0Ch
sMSB3     equ 0Dh
sX3       equ 0Eh
sY3       equ 0Fh
sLSB4     equ 10h
sMSB4     equ 11h
sX4       equ 12h
sY4       equ 13h
sLSB5     equ 14h
sMSB5     equ 15h
sX5       equ 16h
sY5       equ 17h
sLSB6     equ 18h
sMSB6     equ 19h
sX6       equ 1Ah
sY6       equ 1Bh
sLSB7     equ 1Ch
sMSB7     equ 1Dh
sX7       equ 1Eh
sY7       equ 1Fh
sUpdate   equ 20h
key0      equ 21h
key1      equ 22h
key2      equ 23h
key3      equ 24h
key4      equ 25h
key5      equ 26h
key6      equ 27h
keyMask   equ 28h
sMask     equ 29h
;
;
status    equ 2Ch     ;bit 7 set means turn the system off

;RAM equates
stackptr  equ 2Ah+saveSScreen
PClow     equ 2Bh+saveSScreen     ;** note that the upper bit of PC is in the status port

stackbase equ 80h
Spoiler For Instruction Set:

;Instr   arg1   arg2   arg3   hex
ld   (addr1),(addr2)      00xxyy
add   (addr1),(addr2)      01xxyy
adc   (addr1),(addr2)      02xxyy
sub   (addr1),(addr2)      03xxyy
sbc   (addr1),(addr2)      04xxyy
xor   (addr1),(addr2)      05xxyy
or   (addr1),(addr2)      06xxyy
and   (addr1),(addr2)      07xxyy
cp   (addr1),(addr2)      08xxyy
inc   (addr1)         09xx
push   (addr1)         0Axx
pop   (addr1)         0Bxx
ret            0C
ret z            0D
ret c            0E
ldir   (addr1),size,   data   0Fxxyy[data]

ld   (addr1),const      10xxyy
add   (addr1),const      11xxyy
adc   (addr1),const      12xxyy
sub   (addr1),const      13xxyy
sbc   (addr1),const      14xxyy
xor   (addr1),const      15xxyy
or   (addr1),const      16xxyy
and   (addr1),const      17xxyy
cp   (addr1),const      18xxyy
dec   (addr1)         19xx
push   const         1Axx         ;not added yet
ex   (addr1),(addr2)      1Bxxyy       ;not added yet
ldir   addr1   ,size,   data   1Fxxyy[data]

jrf   const         30xx
jrb   const         33xx


Currently the program is 522 bytes, but I still need to add in a decent sprite routine (I will probably use some heavy SMC).

Yay, the ports have been added :) I made a more complicated program and I changed the port values so now each group of sprite ports is five bytes (the fifth is for the drawing method). The code isn't clean, but it shows that it is working. The code in the screenshot increments the x coordinate of the first sprite until [Clear] is pressed. It doesn't wait to acknowledge if the sprite has been drawn which is why I consider it to not be cleaned up code.

Also, the hex is compressed using BatLib, so if you want to give it a try, you will need to use BatLib or some other method of compressing the code.

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: Jade
« Reply #20 on: March 02, 2013, 08:24:38 pm »
What's the difference between the two ldir's?

EDIT: And i believe this is the code in "assembly":
Spoiler For jadeDemo.asm:
#include "Jade.inc"
   .org $00
   jrf start   ;$3020
something1:
.db 00
.db 00
.db 00
.db 00
.db 00
.db 00
.db 00
.db 00

light_ball:
.db $3C
.db $42
.db $81
.db $81
.db $81
.db $81
.db $42
.db $3C

something2:
.db 00
.db 00
.db 00
.db 00
.db 00
.db 00
.db 00
.db 00

dark_ball:
.db $3C
.db $7E
.db $FF
.db $FF
.db $FF
.db $FF
.db $7E
.db $3C

start:
   ldir keyMask,4         ;not sure what this does...?
      .db 03,03,01,03   ;enable key0/1,sprites 0/1,turn on LCD update, and ???
   ldir sAddress,10      ;load the two sprites
      .dw 256+light_ball \ .db 03,03,02   ;x,y,sprite type
      .dw 256+dark_ball \ .db $55,$35,02   ;x,y,sprite type
loop:
   add (sX0),$01
   cp (key1),kClear      ;$BF
   jrf z,quit
   jrb loop
quit:
   ld (sMask),$80
Btw, i think you accidentally put in an extra sMethod before sUpdate, so some of the equates at the end are one byte off. Here's an include file i've started but haven't tested/finished yet:
Spoiler For jade.inc:
#define lda(addr1,addr2)   .db $00,addr1,addr2
#define adda(addr1,addr2)   .db $01,addr1,addr2
#define adca(addr1,addr2)   .db $02,addr1,addr2
#define suba(addr1,addr2)   .db $03,addr1,addr2
#define sbca(addr1,addr2)   .db $04,addr1,addr2
#define xora(addr1,addr2)   .db $05,addr1,addr2
#define ora(addr1,addr2)   .db $06,addr1,addr2
#define anda(addr1,addr2)   .db $07,addr1,addr2
#define cpa(addr1,addr2)   .db $08,addr1,addr2
#define inc(addr1)         .db $09,addr1
#define push(addr1)         .db $0A,addr1
#define pop(addr1)         .db $0B,addr1
#define ret               .db $0C
#define ret z            .db $0D
#define ret c            .db $0E
;#define ldira(addr1,size)   .db $0F,addr1,size
#define ldc(addr1,const)   .db $10,addr1,const
#define addc(addr1,const)   .db $11,addr1,const
#define adcc(addr1,const)   .db $12,addr1,const
#define subc(addr1,const)   .db $13,addr1,const
#define sbcc(addr1,const)   .db $14,addr1,const
#define xorc(addr1,const)   .db $15,addr1,const
#define orc(addr1,const)   .db $16,addr1,const
#define andc(addr1,const)   .db $17,addr1,const
#define cpc(addr1,const)   .db $18,addr1,const
#define dec(addr1)         .db $19,addr1
;#define push(addr1)      .db $1A,addr1
;#define ex(addr1,addr2)   .db $1B,addr1,addr2
#define ldirc(addr1,size)   .db $1F,addr1,size
#define jrf(const)         .db $30,const-$-1
#define jrfc(const)         .db $31,const-$-1
#define jrfz(const)         .db $32,const-$-1
#define jrb(const)         .db $33,$-const
#define jrbc(const)         .db $33,$-const
#define jrb(const)         .db $33,$-const

;ports
sprite0   = 00h
sLSB0   = 00h
sMSB0   = 01h
sX0      = 02h
sY0      = 03h
sMethod0  = 04h
sLSB1   = 05h
sMSB1   = 06h
sX1      = 07h
sY1      = 08h
sMethod1  = 09h
sLSB2   = 0Ah
sMSB2   = 0Bh
sX2      = 0Ch
sY2      = 0Dh
sMethod2  = 0Eh
sLSB3   = 0Fh
sMSB3   = 10h
sX3      = 11h
sY3      = 12h
sMethod3  = 13h
sLSB4   = 14h
sMSB4   = 15h
sX4      = 16h
sY4      = 17h
sMethod4  = 18h
sLSB5   = 19h
sMSB5   = 1Ah
sX5      = 1Bh
sY5      = 1Ch
sMethod5  = 1Dh
sLSB6   = 1Eh
sMSB6   = 1Fh
sX6      = 20h
sY6      = 21h
sMethod6  = 22h
sLSB7   = 23h
sMSB7   = 24h
sX7      = 25h
sY7      = 26h
sMethod7  = 27h
sUpdate   = 28h
key0   = 29h
key1   = 2Ah
kClear   = $BF
key2   = 2Bh
key3   = 2Ch
key4   = 2Dh
key5   = 2Eh
key6   = 2Fh
keyMask   = 30h
sMask   = 31h
status   = 32h   ;bit 7 set means turn the system off, bit 0 = LCD update
sTimer   = 33h

;RAM =ates
saveSScreen = 9872h
stackptr   = 35h+saveSScreen
PClow      = 36h+saveSScreen   ;** note that the upper bit of PC is in the status port

stackbase = 80h

OP6 = 84AFh
TempWord1 = OP6
TempWord2 = OP6+2
TempWord3 = OP6+4

I just compiled and ran this code (typing it in by hand) just fine on my 83+ :)
Code: [Select]
#include "jade.inc"
.org $00
jrf(start)
sprite:
.db $FF
.db $FF
.db $FF
.db $FF
.db $FF
.db $FF
.db $FF
.db $FF
start:
ldirc(keyMask,3)
.db 3,3,1
ldirc(sprite0,5)
.dw $100+sprite \ .db 0,0,2
loop:
cpc(key1,kClear)
jrfz(quit)
jrb(loop)
quit:
ldc(status,$80)
« Last Edit: March 02, 2013, 10:45:51 pm by chickendude »

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Jade
« Reply #21 on: March 03, 2013, 06:32:49 am »
The two LDIRs are different in that one writes to a fixed address (1F.address.size.data) and the other uses a byte in RAM to figure out where to write the data.

And yes, I saw that I had an extra sMethod after I got offline, sorry .__. Your assembly translation is exactly correct, too!

The extra 3 after the LCD update thingy is something I forgot to document and that is the frequency for updating the sprites. 3 means it updates a sprite every three instructions, so this can really slow down code as you might imagine. As a note, this doesn't update all of the sprites at once, only one sprite at a time. It also updates the LCD when each sprite is drawn, so I should probably change that to update only after all the sprites are scanned.

Also, looking at your code, I like your naming syntax better for cpc, ldc, and ldirc. It makes more sense. I was actually worried that cpc() would not work, so I am glad that it does!

For the .inc file, that is lovely! Any ideas on a good port 34h? Also, saveSScreen is typically 86ECh, but it will work on 9872h, too.

Another thing that I realised is that savestates can be 128 bytes or 256 bytes, depending on the RAM being used.

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: Jade
« Reply #22 on: March 03, 2013, 09:43:21 am »
I've been having a bit of trouble getting other keys to work correctly, maybe i'm not quite doing something right or maybe i'm missing something. Anyway, i've got this code (which when thinking of how it might translate into assembly makes me shiver :P):
Spoiler For move a sprite:
Code: [Select]
#include "jade.inc"
.org $00
jrf(start)
sprite:
.db %00111100
.db %01100110
.db %11000011
.db %11100111
.db $FF
.db $FF
.db $FF
.db $FF
start:
ldirc(keyMask,3)
.db 3,1,1
ldirc(sprite0,5)
.dw $100+sprite \ .db 0,0,2
loop:
cpc(key0,kDown)
jrfz(goDown)
cpc(key0,kUp)
jrfz(goUp)
cpc(key0,kLeft)
jrfz(goLeft)
cpc(key0,kRight)
jrfz(goRight)
cpc(key1,kClear)
jrfz(quit)
jrb(loop)
goDown:
addc(sY0,1)
jrb(loop)
goUp:
subc(sY0,1)
jrb(loop)
goLeft:
subc(sX0,1)
jrb(loop)
goRight:
addc(sX0,1)
jrb(loop)
quit:
ldc(status,$80)
I assumed you're using direct input values and made these defines:
Code: [Select]
;##_key 0_##
key0 = 29h
kDown = $FE
kLeft = $FD
kRight = $FB
kUp = $F7
The sprite doesn't really seem to move, however. Sometimes it will jump to the middle of the top row, but never moves up or down. I've also gotten a couple crashes so far, some from mistyping the hex ;) Can you think of an easier way to transfer programs apart from typing them by hand? I tried prefixing the quote with the " token and ending it with ->Str0, but when running the basic interpreter complains about some of the compiled tokens and it won't store the entire string into Str0. Another idea might be a little [On]+[Clear] interrupt to forceably quit a program.

The ion include file i downloaded from ticalc has this:
Code: [Select]
;saferam1 =86ECh
saferam1 =9872h
but then i double checked one of my own projects and saw this:
Code: [Select]
;saferam1 =$86EC ;saveSScreen=768
;saferam2 =$8A3A ;statVars=531
;saferam3 =$8508 ;textShadow=128
;saferam4 =$8478 ;OPs=66
;saferam5 =$84D3 ;iMathPtrs=10
;saferamp =$9872 ;appBackUpScreen=768
;saferamp2 =$8251 ;bootTemp=52
;gbuf =$9340 ;768
;graphVariables =$8E67 ;1179 : 494+126(financeVars)+108(smallEditRAM)+157(plus de graphs)+294(tableStuff)
so... $86EC it is ;)

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Jade
« Reply #23 on: March 03, 2013, 05:06:36 pm »
Hmm, I think I know the problems:

I have an issue with the keypresses and it apparently isn't reading the last key group.
I have an issue with the sprite drawing (I forgot to include clipping), so this probably caused any crashes.
The reason for why it seems like you aren't moving the sprite is because with a sprite delay of 0, it is actually being interpreted as 256. Essentially, when you press a key like the left key in your code, it is incrementing the X coordinate a bunch of times before the update
Without updating the sprite so often, code is executed pretty quickly. I think it averages about 10000 instructions per second. To set up the update timer, try:
Code: [Select]
ldirc(keyMask,4)
  .db 3,1,1,1
The last '1' says to update the next sprite at each instruction. Keep in mind that it cycles through each sprite one at a time, so Sprite0 gets updated every 8th instruction. With a delay of 256, there was time for 2048 instructions to execute and pressing down looped through 4 instructions in your code meaning Y could get incremented 512 times before updating the sprite.

To answer your question about making an easier way to make/edit programs, I should have probably mentioned that the code can be in a program or appvar. So if you can get some kind of assembler to compile the code to a program, you can do something like:
Code: [Select]
"[JADETEST":Asm(prgmJADE
And that will execute the program named JADETEST as a JADE program. Use '5' instead of '[' to execute an appvar.

Now I have a few propositions for changes to the current instruction set and port setup. After trying to code in this language, it is obviuos that it is rather clunky. So I want to use an idea that Runer suggested that might make the code smaller and faster. Right now, all of the instructions fit in 6 bits, but take up a byte. I could make all of the instruction have flag arguments. For example, you could do something like this:
Code: [Select]
Loop:
 cpc(key0,kDown)
 incz(sY0)
 cpc(key0,kUp)
 decz(sY0)
 cpc(key0,kLeft)
 incz(sX0)
 cpc(key0,kRight)
 decz(sX0)
 cpc(key1,kClear)
 ldcz(status,$80)
 jrb(Loop)
And that would be the code to move the coordinates of the sprite, which is 20 bytes compared to 50 bytes.

If I do this, then we will free up room for other types of instructions, too. For example, I think an instruction to set, reset, or toggle a flag is useful, as well as these commands:
Code: [Select]
  bits(const,addr)   ;will perform bitwise AND logic, but doesn't change (addr), only flags. Useful to see if one of the bits is set.
  inv(addr)          ;invert the bits
  rotl(addr)         ;rotate the bits left
  rotr(addr)         ;rotate the bits right
  shftl(addr)        ;shift the bits left
  shftr(addr)        ;shift the bits right
Here is my proposed outline for a new instruction set:
Code: [Select]
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 lda() adda() adca() suba() sbca() xora() ora() anda() cpa() inc() rotl() shftl() pusha() pop() inv() ldira()
1 ldc() addc() adcc() subc() sbcc() xorc() orc() andc() cpc() dec() rotr() shftr() pushc() ex() bits() ldirc()
2 ret() setz() setc() togz() togc() jp1() jp2() jrf() jrb() call1() call2() callf() callb()
3
;Duplicate for execution on the c flag condition
4x,5x,6x,7x
;Duplicate for execution on the z flag condition
8x,9x,Ax,Bx
;???
Cx,Dx,Ex,Fx
There will then be room for 19 more instructions and possibly 64 more depending on what is done for the last set. As a quick note,these instructions are not included:
Code: [Select]
resz() resc()
These are equivalent to:
Code: [Select]
togzz() togcc()
For example, togzz() will only toggle the z flag if the z flag is set,so it only resets the z flag.

Proposed changes to the ports:
We need a better way to handle sprites. I have a few ideas:
  • Draw a sprite only if sMask has the bit set and sUpdate has the bit reset.

Implications: When a sprite is drawn, sUpdate gets the corresponding bit set. This means that in order to update the sprite again, you need to reset the bit, essentially acknowledging that it has been drawn. This will allow the programmer to do proper cleanup on the LCD.
  • Only update the LCD when bit 0 of the status port is set and Sprite7 has been drawn.

Implications: It is faster than updating the LCD every time a sprite is drawn and looks cleaner.
  • When the LCD is updated, reset bit 0 of the status port.

Implications: All the sprites are drawn, so if you need to cleanup the buffer you can without the screen being updated.
  • If these changes are made, the sTimer port can be removed and updates will be made as the ports are edited.


So if all of these changes are made, here is an example routine for moving a sprite:
Code: [Select]
#include "jade.inc"
.org $00
 jrf(start)
sprite:
.db %00111100
.db %01100110
.db %11000011
.db %11100111
.db $FF
.db $FF
.db $FF
.db $FF
start:
 ldirc(sprite0,5)
  .dw $100+sprite \ .db 0,0,2
 ldirc(keyMask,2)
  .db 3,1
Loop:
 orc(status,1)        ;set bit 0 of the status port
KeyLoop:
 cpc(key1,kClear)     ;Check if clear is pressed
 ldcz(status,$80)     ;Turn off Jade if the z flag is set by writing 80h to the status port
 cpc(key0,-1)         ;test if no keys are being pressed
 jrbz(KeyLoop)

 callf(SpriteWait)    ;In case not enough time has passed for the sprite to be drawn
 ldc(sUpdate,0)       ;Acknowledge the sprite drawing, allowing it to redraw the sprite (XORing twice results in no change)
 callf(SpriteWait)    ;We need to wait until the sprite is drawn before updating coordinates

 cpc(key0,kDown)
 incz(sY0)
 cpc(key0,kUp)
 decz(sY0)
 cpc(key0,kLeft)
 incz(sX0)
 cpc(key0,kRight)
 decz(sX0)
 ldc(sUpdate,0)       ;Acknowledge any sprites drawn, allowing the updated coordinates to be displayed
 jrb(Loop)

SpriteWait:
 cpa(sUpdate,sMask)   ;Check if all of the sprites are drawn
 retz()
 jrb(SpriteWait)

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: Jade
« Reply #24 on: March 04, 2013, 01:32:49 am »
I really like the idea of the conditional codes. It's something i really like about ARM assembly, pretty much any instruction can take conditions. So you can do things like addc r1,r2 or even cmpz r1,r2. You can actually also add shifts, so you can do addc r1,r2,r3 LSL 4, which adds r2 + [r3 shifted to the left 4 bits] and stores the result in r1, but only if the carry flag is set (that's one instruction!) :P

Right now, what does sMask do? I assumed that a sprite wouldn't be processed unless you turned on that sprite's corresponding sMask bit. If i set the sprite delay to 1 and only have one sprite set in the sMask, it'll still process the other 7 sprites before coming back to the one i've enabled?

Also, a double-buffer might work really well here since with 8 sprites not a lot of the screen should be changing at once:
http://wikiti.brandonw.net/index.php?title=Z80_Routines:Graphic:Fastcopy#Double-buffered_copy

I think your other ideas are also good, in particular updating the LCD after each sprite is drawn will probably cause quite a bit of a slowdown. Waiting until all sprites have been drawn before updating is probably a good idea. I was also wondering if bit-instructions were going to be added :D

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Jade
« Reply #25 on: March 04, 2013, 06:41:30 am »
I really like the idea of the conditional codes. It's something i really like about ARM assembly, pretty much any instruction can take conditions. So you can do things like addc r1,r2 or even cmpz r1,r2. You can actually also add shifts, so you can do addc r1,r2,r3 LSL 4, which adds r2 + [r3 shifted to the left 4 bits] and stores the result in r1, but only if the carry flag is set (that's one instruction!) :P
Awesome, that sounds so cool o.o
Right now, what does sMask do? I assumed that a sprite wouldn't be processed unless you turned on that sprite's corresponding sMask bit. If i set the sprite delay to 1 and only have one sprite set in the sMask, it'll still process the other 7 sprites before coming back to the one i've enabled?
Yes, that is how sMask works. Processing is rather quick if the sprite is not to be drawn, though.
Also, a double-buffer might work really well here since with 8 sprites not a lot of the screen should be changing at once:
http://wikiti.brandonw.net/index.php?title=Z80_Routines:Graphic:Fastcopy#Double-buffered_copy
Hehe, I have a double buffer routine ready, but in the current version I just use the horribly slow OS routine _GrBufCpy. The way I plan to implement it should update the screen slightly faster than the code linked to, only because I keep the habit of setting the X coordinate at the beginning of the program (the one that is 0 to 63). Since my routine returns with it being the same, there is no need to keep setting that coordinate.
I think your other ideas are also good, in particular updating the LCD after each sprite is drawn will probably cause quite a bit of a slowdown. Waiting until all sprites have been drawn before updating is probably a good idea. I was also wondering if bit-instructions were going to be added :D
:) Currently, you can set bits using orc() and reset bits with andc() and toggle with xorc(), but testing bits is more complicated without modifying RAM, so that is why I wanted to add the bits() command.

There is one thing that is very lacking with this system and that is pixel testing for collision detection. However, we can use the sprite coordinates to figure out if they collide with each other.

EDIT: I started work on rewriting the whole code for the new instruction set. I only have a few more instructions to finish and it is only 472 bytes. I still need to add in two larger pieces of code, though, so I think the size will be around 900 bytes when finished. It should be a bit faster than before, too, and coding should be cleaner.

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: Jade
« Reply #26 on: March 05, 2013, 06:27:44 pm »
Please let us know when the next version is ready to test out :D

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Jade
« Reply #27 on: March 11, 2013, 12:00:14 pm »
I totally rewrote the sprite drawing routine and now there are only three methods of drawing sprites :/ On the other hand, I fixed clipping and made it faster. Currently Jade has the instruction set working (or it appears to be working), but I cannot figure out why the LCD is being updated when it shouldn't be, so I am probably going to make Jade update all sprites at once, if bit 1 of the status port is set. That will just make it easier and smaller to code with sprites. As it is, here is a current screenshot :)

EDIT: Well that was quick o.o I have it working now the way it was supposed to. Compare the first screenshot to the second XD And now here is a download. The code in the new screenshot is:
Spoiler For Jade.inc:
;ports
sLSB0     equ 00h
sMSB0     equ 01h
sX0       equ 02h
sY0       equ 03h
sMethod0  equ 04h
sLSB1     equ 05h
sMSB1     equ 06h
sX1       equ 07h
sY1       equ 08h
sMethod1  equ 09h
sLSB2     equ 0Ah
sMSB2     equ 0Bh
sX2       equ 0Ch
sY2       equ 0Dh
sMethod2  equ 0Eh
sLSB3     equ 0Fh
sMSB3     equ 10h
sX3       equ 11h
sY3       equ 12h
sMethod3  equ 13h
sLSB4     equ 14h
sMSB4     equ 15h
sX4       equ 16h
sY4       equ 17h
sMethod4  equ 18h
sLSB5     equ 19h
sMSB5     equ 1Ah
sX5       equ 1Bh
sY5       equ 1Ch
sMethod5  equ 1Dh
sLSB6     equ 1Eh
sMSB6     equ 1Fh
sX6       equ 20h
sY6       equ 21h
sMethod6  equ 22h
sLSB7     equ 23h
sMSB7     equ 24h
sX7       equ 25h
sY7       equ 26h
sMethod7  equ 27h
key0      equ 28h
key1      equ 29h
key2      equ 2Ah
key3      equ 2Bh
key4      equ 2Ch
key5      equ 2Dh
key6      equ 2Eh
keyMask   equ 2Fh
sMask     equ 30h
status    equ 31h     ;bit 7 set means turn the system off, bit 0 = LCD update

;RAM equates
stackptr  equ 32h
PClow     equ 33h+saveSScreen
PChigh    equ 34h+saveSScreen
stackbase equ 80h+saveSScreen


_FlashToRam2        equ 8054h
#define    lda(addr1  , addr2)     .db 0,addr1,addr2
#define    adda(addr1 , addr2)     .db 1,addr1,addr2
#define    adca(addr1 , addr2)     .db 2,addr1,addr2
#define    suba(addr1 , addr2)     .db 3,addr1,addr2
#define    sbca(addr1 , addr2)     .db 4,addr1,addr2
#define    xora(addr1 , addr2)     .db 5,addr1,addr2
#define    ora(addr1  , addr2)     .db 6,addr1,addr2
#define    anda(addr1 , addr2)     .db 7,addr1,addr2
#define    cpa(addr1  , addr2)     .db 8,addr1,addr2
#define    inc(addr)               .db 9,addr
#define    rotl(addr)              .db 10,addr
#define    shftl(addr)             .db 11,addr
#define    pusha(addr)             .db 12,addr
#define    pop(addr)               .db 13,addr
#define    inv(addr)               .db 14,addr
#define    ldira(addr,size)        .db 15,addr,size

#define    ldc(addr  , const)      .db 16,addr,const
#define    addc(addr , const)      .db 17,addr,const
#define    adcc(addr , const)      .db 18,addr,const
#define    subc(addr , const)      .db 19,addr,const
#define    sbcc(addr , const)      .db 20,addr,const
#define    xorc(addr , const)      .db 21,addr,const
#define    orc(addr  , const)      .db 22,addr,const
#define    andc(addr , const)      .db 23,addr,const
#define    cpc(addr  , const)      .db 24,addr,const
#define    dec(addr)               .db 25,addr
#define    rotr(addr)              .db 26,addr
#define    shftr(addr)             .db 27,addr
#define    pushc(const)            .db 28,const
#define    ex(addr1,addr2)         .db 29,addr1,addr2
#define    bits(addr,const         .db 30,addr,const
#define    ldirc(addr,size)        .db 31,addr,size

#define    ret()                   .db 32
#define    setz()                  .db 33
#define    setc()                  .db 34
#define    togz()                  .db 35
#define    togc()                  .db 36
#define    jp1(Addr)               .db 37,Addr
#define    jp2(Addr)               .db 38,Addr
#define    jrf(offset)             .db 39,offset-1-$
#define    jrb(offset)             .db 40,1-offset+$
#define    call1(Addr)             .db 41,Addr
#define    call2(Addr)             .db 42,Addr
#define    callf(offset)           .db 43,offset-1-$
#define    callb(offset)           .db 44,1-offset+$

#define    ldcz(addr1  , const)    .db 16+128,addr1,const
#define    jrbz(offset)            .db 40+128,1-offset+$
#define    incz(addr)              .db 9+128,addr
#define    decz(addr)              .db 25+128,addr
#define    retz()                  .db 32+128

jkDown     equ %11111110
jkRight    equ %11111101
jkLeft     equ %11111011
jkUp       equ %11110111
jkClear    equ %10111111

lcdupdatebit       equ 0
spriteupdatebit    equ 1

Code: [Select]
#include 'Jade.inc'
.org $00
 jrf(start)
sprite:
.db %00111100
.db %01100110
.db %11000011
.db %11100111
.db $FF
.db $FF
.db $FF
.db $FF
start:
 ldirc(sLSB0,5)
  .dw $100+sprite \ .db 0,0,2
 ldirc(keyMask,2)
  .db 3,1             ;
Loop:
 orc(status,2)        ;set bit 1 of the status port to draw the sprites
 orc(status,3)        ;set bit 0 and 1 of the status port to update the LCD, then redraw the sprites
KeyLoop:
 cpc(key1,jkClear)    ;Check if clear is pressed
 ldcz(status,$80)     ;Turn off Jade if the z flag is set by writing 80h to the status port
 cpc(key0,-1)         ;test if no keys are being pressed
 jrbz(KeyLoop)


 cpc(key0,jkDown)
 incz(sY0)
 cpc(key0,jkUp)
 decz(sY0)
 cpc(key0,jkLeft)
 incz(sX0)
 cpc(key0,jkRight)
 decz(sX0)
 jrb(Loop)
Now I need to try to document everything .__.


Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Jade
« Reply #28 on: March 11, 2013, 06:31:55 pm »
Yay, double posting. I found two bugs in Jade. The first made several commands work incorrectly:
cpa()
cpc()
suba()
subc()
sbca()
sbcc()

And the second one prevented the c flag from being set (I used rlc instead of rl). So I have those fixed, and I started Pong. Click the screenie for the download :)

The code for that is precisely 200 bytes and the code is:
Code: [Select]
#include     "ti83plus.inc"
#include     "Jade.inc"
.org 0
scratchmath  equ  252
scratchmath1 equ  253
ballxinc     equ  254
ballyinc     equ  255

Start:
     ldirc(sLSB0,25)
       .dw $100+ball \ .db 3,3,2  ;load the sprite data for Sprite0. The 2 is for XOR logic.
       .dw $100+paddle \ .db 0,24,2  ;load the sprite data for Sprite1. The 2 is for XOR logic.
       .dw $100+paddle \ .db 0,32,2  ;load the sprite data for Sprite2. The 2 is for XOR logic.
       .dw $100+paddle \ .db 94,24,2  ;load the sprite data for Sprite3. The 2 is for XOR logic.
       .dw $100+paddle \ .db 94,32,2  ;load the sprite data for Sprite4. The 2 is for XOR logic.
     ldirc(keyMask,2)
       .db %00010110,31              ;the second byte is for sMask (the sprite mask)
     ldc(ballxinc,1)
     ldc(ballyinc,1)
Loop:
     orc(status,2)      ;tell the status port to draw the sprites
     orc(status,3)      ;tell the status port to update the LCD, then draw the sprites
KeyLoop:
     bits(key1,40h)     ;check for the Clear key being pressed
     orcz(status,80h)   ;sets bit 7 of the status port if the z flag is set. This turns off Jade.
     bits(key2,2)       ;check if player 2 down key is being pressed
     togz()
     jrfz(TestP2Up)
     cpc(sY3,48)
     jrfz(TestP2Up)
     addc(sY3,2)
     addc(sY4,2)
TestP2Up:
     bits(key2,8)       ;check if player 2 down key is being pressed
     togz()
     jrfz(TestP1Down)
     cpc(sY3,0)
     jrfz(TestP1Down)
     subc(sY3,2)
     subc(sY4,2)
TestP1Down:
     bits(key4,2)       ;check if player 2 down key is being pressed
     togz()
     jrfz(TestP1Up)
     cpc(sY1,48)
     jrfz(TestP1Up)
     addc(sY1,2)
     addc(sY2,2)
TestP1Up:
     bits(key4,8)       ;check if player 2 down key is being pressed
     togz()
     jrfz(MoveBall)
     cpc(sY1,0)
     jrfz(MoveBall)
     subc(sY1,2)
     subc(sY2,2)
MoveBall:
     adda(sX0,ballxinc)
     callfz(TestP1Collision)
     cpc(sX0,89)
     callfz(TestP2Collision)
     adda(sY0,ballyinc)
     jrfz(NegYinc)
     cpc(sY0,60)
     togz()
     jrbz(Loop)
NegYinc:
     inv(ballyinc)
     inc(ballyinc)
     jrb(loop)

TestP1Collision:
     lda(scratchmath,sY1)
     jrf(CheckBounds)
TestP2Collision:
     lda(scratchmath,sY3)
CheckBounds:
     lda(scratchmath1,scratchmath)
     subc(scratchmath,3)
     ldcc(scratchmath,0)
     suba(scratchmath,sY0)
     jrfc(CheckOtherBound)
LoseCode:
     ldc(status,80h)
CheckOtherBound:
     addc(scratchmath1,15)
     suba(scratchmath1,sY0)
     jrbc(LoseCode)
NegXinc:
     inv(ballxinc)
     inc(ballxinc)     
     ret()
     
ball:
     .db 18h
     .db 24h
     .db 24h
     .db 18h
     .db 0,0,0,0
paddle:
     .db $C0
     .db $C0
     .db $C0
     .db $C0
     .db $C0
     .db $C0
     .db $C0
     .db $C0
Use [3] and [9] to move the paddle of player 2 and [1] and [7] for Player 1. [Clear] exits.
EDIT: I was trying to write an oncalc compiler thing for Jade earlier when I remembered about this project: ASMDREAM
So after an hour of working on a compiler I decided to instead incorporate ASMDream's system using macros and it works! All of the instructions and equates have been made except for one area-- the header. What sort of header should I use for Jade files? I was thinking there could be several types of files:
ROMs
ROM packs (multiple ROMs in one file)
Save states
So I thought headers might consist of:
Code: [Select]
1 byte for the file info and type
   bit 0:1 for the type
   bit 2 for the save state size (128 bytes or 256)
   bit 3 set if there is a description
   bit 4 set if there is an icon
1 bytes for the name length
n bytes for the name
2 bytes for the miscellaneous data size
n bytes for miscellaneous data such as description and icon
2 bytes for the ROM size
n bytes for ROM data

Hopefully this is will make it easier for people to code for Jade :)

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Jade
« Reply #29 on: March 12, 2013, 02:38:35 pm »
I started the documentation and I am not sure if I have forgotten anything. About the header stuff, I thought that I would add an on-calc utility for adding a header to a file. I had issues with trying to get an assembler to work properly (because you need to do '.org 0' after the header). I still haven't added anything to Jade since the last update except code to let you press ON to turn Jade off.

A few other things that I was thinking about adding:
For the sprites, if you add 4 to the sprite method, then the first byte of the sprite data indicates the height of the sprite. In the Pong example, I currently use the same sprite twice for each paddle to make it 16 units long (so the same sprite is drawn 4 times to different locations). As well, the ball only needs to be 4 bytes instead of 8 (though it could be compressed to 2 bytes).

Type 8 can instead draw a string as opposed to a sprite. It feels like cheating, but haven't other systems done this?
Type 9 can draw a 16-bit signed number
Type 10 can draw an inverted rectangle
Type 11 can draw a filled rectangle
Type 12 can draw a white rectangle


I may not actually add these, but they are ideas.