flat assembler
Message board for the users of flat assembler.

Index > Non-x86 architectures > DCPU-16

Author
Thread Post new topic Reply to topic
MattDiesel



Joined: 31 Oct 2010
Posts: 34
Location: England
MattDiesel 04 Apr 2012, 14:58
As with anything notch does, I am really excited about this:

http://0x10c.com/

People have already written assemblers for the specification, but I think it would be great to adapt fasm to be able to use it for this. Not least because it would then be very easy to add more complex instructions in the form of macros.

It should be possible with just macros, but I've had a few problems with even basic instructions, as I can't change the output for [0x1000] and similar statements.

I have tried something like:

[ fix MEM(
] fix )

To try and change it to be a macro that I can then do something with, but that didn't work. The alternative would be some way to detect if a parameter is enclosed in [] from a macro.

_________________
Cogito Cogito Ergo Essum
Post 04 Apr 2012, 14:58
View user's profile Send private message Send e-mail Visit poster's website MSN Messenger Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 04 Apr 2012, 16:11
It's relatively easy to do it with fasm's macros, but with one serious problem: fasm calculates label values with byte granularity, while this CPU uses addresses with word granularity. So I had to create a special macro LABEL to define labels, otherwise you'd always have to divide all label values by 2 when using them.

Here are my macros:
Code:
A equ eax
B equ ebx
C equ ecx
X equ edx
Y equ ebp
Z equ esp
I equ esi
J equ edi

@A = 0
@B = 1
@C = 2
@X = 3
@Y = 4
@Z = 5
@I = 6
@J = 7

@SET = 0x1
@ADD = 0x2
@SUB = 0x3
@MUL = 0x4
@DIV = 0x5
@MOD = 0x6
@SHL = 0x7
@SHR = 0x8
@AND = 0x9
@BOR = 0xA
@XOR = 0xB
@IFE = 0xC
@IFN = 0xD
@IFG = 0xE
@IFB = 0xF

@JSR = 0x01

macro parse_operand value {
   define v value
   @nextword = -1
   match =POP,v \{
     define v
     @value = 0x18
   \}
   match =PEEK,v \{
     define v
     @value = 0x19
   \}
   match =PUSH,v \{
     define v
     @value = 0x1A
   \}
   match =SP,v \{
     define v
     @value = 0x1B
   \}
   match =PC,v \{
     define v
     @value = 0x1C
   \}
   match =O,v \{
     define v
     @value = 0x1D
   \}
   match [addr],v \{
     define v
     if +addr relativeto 0
       @value = 0x1E
       @nextword = word addr
     irps reg,A B C X Y Z I J \\{
       else if +addr relativeto reg
         if +addr-reg = 0
           @value = 0x08 + @\\#reg
         else
           @value = 0x10 + @\\#reg
           @nextword = +addr-reg
         end if
     \\}
     end if
   \}
   match expr,v \{
     define v
     if +expr relativeto 0
       if expr>=0 & expr<=0x1F
         @value = 0x20 + expr
       else
         @value = 0x1F
         @nextword = word expr
       end if
     irps reg,A B C X Y Z I J \\{
       else if +expr relativeto reg
         assert +expr-reg = 0
         @value = 0x00 + @\\#reg
     \\}
     end if
   \}
}

macro basic_instruction opcode,a,b {
  @word1 = opcode and 1111b
  parse_operand a
  @word1 = @word1 or @value shl 4
  @word2 = @nextword
  parse_operand b
  @word1 = @word1 or @value shl (4+6)
  @word3 = @nextword
  db @word1 shr 8,@word1 and 0FFh
  if @word2>=0
    db @word2 shr 8,@word2 and 0FFh
  end if
  if @word3>=0
    db @word3 shr 8,@word3 and 0FFh
  end if
}

macro nonbasic_instruction opcode,a {
  @word1 = (opcode and 111111b) shl 4
  parse_operand a
  @word1 = @word1 or @value shl (4+6)
  db @word1 shr 8,@word1 and 0FFh
  if @nextword>=0
    db @nextword shr 8,@nextword and 0FFh
  end if
}

irps instr,SET ADD SUB MUL DIV MOD SHL SHR AND BOR XOR IFE IFN IFG IFB {
  macro instr a,b \{ basic_instruction @\#instr,a,b \}
}

irps instr,JSR {
  macro instr a \{ nonbasic_instruction @\#instr,a \}
}

macro LABEL name {
  name = $ shr 1
}    

and converted example code (note that everything is case-sensitive):
Code:
; Try some basic stuff
              SET A, 0x30
              SET [0x1000], 0x20
              SUB A, [0x1000]
              IFN A, 0x10
              SET PC, crash

; Do a loopy thing
              SET I, 10
              SET A, 0x2000
LABEL _loop
              SET [0x2000+I], [A]
              SUB I, 1
              IFN I, 0
              SET PC, _loop

; Call a subroutine
              SET X, 0x4
              JSR testsub
              SET PC, crash

LABEL testsub
              SHL X, 4
              SET PC, POP

; Hang forever. X should now be 0x40 if everything went right.
LABEL crash
              SET PC, crash    
And, of course, fasm optimizes the instructions to short forms automatically. Wink


Still, it would be perhaps better to make a custom fasm version for such architecture. First, it would allow to generate label values correctly divided by 2. Second, it would make instructions and register names not case-sensitive. And third - you would not have to worry about the huge amount of x86 reserved words that fasm doesn't allow to use as label (as with "loop" in the example above).
Post 04 Apr 2012, 16:11
View user's profile Send private message Visit poster's website Reply with quote
MattDiesel



Joined: 31 Oct 2010
Posts: 34
Location: England
MattDiesel 04 Apr 2012, 16:43
But you seem to have it all sorted!

You sir, are a genius.

_________________
Cogito Cogito Ergo Essum
Post 04 Apr 2012, 16:43
View user's profile Send private message Send e-mail Visit poster's website MSN Messenger Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 04 Apr 2012, 19:44
Maybe better put this to "non x86 architectures" forum. Razz
Post 04 Apr 2012, 19:44
View user's profile Send private message Send e-mail Reply with quote
MattDiesel



Joined: 31 Oct 2010
Posts: 34
Location: England
MattDiesel 04 Apr 2012, 21:20
I'm working on implementing some extended features, like procedures (using Z as the base pointer at the moment). Unfortunately I don't fully understand everything going on in PROC32.inc that I was hoping I could replicate. This is what I get for not bothering to learn macros. So far I have very badly implemented stdcall, enter, leave and ret functions.

I also hacked together a disassembler just to check the output of various things: http://dl.dropbox.com/u/49542897/Programming/undcpu.tar.gz

Next thing to write is the emulator, which I'm going to write tomorrow (just a console debugger).

The game has barely started development and I can already tell I'm going to waste a lot of time playing it.

_________________
Cogito Cogito Ergo Essum
Post 04 Apr 2012, 21:20
View user's profile Send private message Send e-mail Visit poster's website MSN Messenger Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2139
Location: Estonia
Madis731 05 Apr 2012, 06:05
When I was young, I was dreaming about a game like this. I thought it would never work because of the nerdy stuff that only some people like. But I can see that they've managed to solve a lot of these problems with duct tape and alike Smile

When I see people crafting ALU-s in Minecraft I think there's a lot of potential. That is going to be a game that I can't wait to play.
Post 05 Apr 2012, 06:05
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger Reply with quote
MattDiesel



Joined: 31 Oct 2010
Posts: 34
Location: England
MattDiesel 05 Apr 2012, 11:38
Just rewrote my disassembler in C (a lot cleaner than C++) with support for more readable output, cycle counting, recognising SET PC, ... etc.

http://pastie.org/pastes/3732465

Using "-railc" (Readable output, no Assembly, Indent if*, show Lines and show Cycles):

Code:
000000  [ 2 ]  A = 0x30
000002  [ 3 ]  [0x1000] = 0x20
000005  [ 3 ]  A = A - [0x1000]
000007  [2+1]  IF ( A != 0x10 )
000008  [ 1 ]      GOTO 0x16
000009  [ 1 ]  I = 0xa
00000a  [ 2 ]  A = 0x2000
00000c  [ 2 ]  [I + 0x2000] = [A]
00000e  [ 2 ]  I = I - 0x1
00000f  [2+1]  IF ( I != 0 )
000010  [ 1 ]      goto 0xc
000011  [ 1 ]  X = 0x4
000012  [ 2 ]  CALL 0x14
000013  [ 1 ]  GOTO 0x16
000014  [ 2 ]  X = X << 0x4
000015  [ 1 ]  RET
000016  [ 1 ]  GOTO 0x16    


Now writing an emulator Smile

_________________
Cogito Cogito Ergo Essum
Post 05 Apr 2012, 11:38
View user's profile Send private message Send e-mail Visit poster's website MSN Messenger Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2139
Location: Estonia
Madis731 06 Apr 2012, 10:25
Intel Compiler gave some warnings about making boolean operations on enums. I changed the first few lines to:
Code:
#define showHex 1
#define showLines 2
#define showCycles 4
#define showHR 8
#define noshowAsm 16
#define showInd 32
int cmdFlags;
    


Fixed some crashes here and there (mostly dealing with reserved/unexpected input):
Code:
    if (o->code.opcode == 0)
 {
              if(o->n.opcode == 1)
             {
                      ret = printf("%s\t", opcodeNames_nbasic[o->n.opcode]);
                        ret += valPrint(o->n.a_type, o->n.a);
         }
              else
                        ret = printf("%s\t", opcodeNames_nbasic[0]);
     }
    

Reserved will not print out instruction costs as [137677396] and similar:
Code:
          if (cmdFlags & showCycles)
              {
                      if(o->b.opcode == 0 && o->n.opcode != 1)
                              printf("[???]  ");
                        else if (o->b.opcode >= 0xC)
                          printf("[%i+1]  ", instrGetCycles(o));
                    else
                                printf("[ %i ]  ", instrGetCycles(o));
            }
    

When I tested all possible input values then the program went into an infinite loop because of the word limitation. The spec says * 0x10000 words of ram which means that maximum address can be 2*65536-2=0x1FFFE in our world, but 0xFFFF in DCPU16 world.
Code:
void instrDisasm(const word inp[], int len)
{
      int cur = 0, delta;
    

I changed cur to int for the program to finish.


...and you're missing code behind -h switch.
Post 06 Apr 2012, 10:25
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger Reply with quote
MattDiesel



Joined: 31 Oct 2010
Posts: 34
Location: England
MattDiesel 10 Apr 2012, 08:55
Thats what you get for getting excited and programming quickly. Loads of bugs.

Thanks for the info, I was only really concerned about getting valid input to work rather than spotting the invalid. I've moved on to trying to write a full C compiler, though I am doing that properly (i.e. more structured) and so it is taking longer.

I am also trying to implement half precision floating point arithmetic for the dcpu16 but that is turning out to be very tricky, and it takes a lot of cycles no matter what I do.

_________________
Cogito Cogito Ergo Essum
Post 10 Apr 2012, 08:55
View user's profile Send private message Send e-mail Visit poster's website MSN Messenger Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2139
Location: Estonia
Madis731 10 Apr 2012, 11:25
Reading material:
http://fail0verflow.com/blog/2012/dcpu-16-review.html
https://twitter.com/#!/notch/status/189533061967380481

I've wondered if DCPU-16 emulator could use AVX effectively. This would theoretically mean that a 2GHz thread could emulate 8 CPUs in parallel and emulation speed at 100kHz means 20000*8=160000 CPUs realtime. Of course there's overhead and the CPI is not exactly 1.0, but roughly 100000 DCPU-16 CPUs emulated on a single thread is amazing Smile

Thinking about the loose timings given in the spec, this might work.
Post 10 Apr 2012, 11:25
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger Reply with quote
r22



Joined: 27 Dec 2004
Posts: 805
r22 10 Apr 2012, 19:33
This looks like the perfect job for JavaScript.

- Simple Regex Match for every instruction, with Match Groups for Register and/or Memory
- An associative array with OPCode objects that have cycle timings, binary encoding help etc.
- More than fast enough to emulate in real-time
- Simple way to add the API input and output elements that will undoubtedly be added.
- - Graphics = HTML Canvas
- - Sound = HTML Audio
- - Input = DOM Mouse/Key Events
- Host the whole thing on a web page

Unfortunately, I prefer mindless entertainment. Programming my space ship's computer sound too much like work. However, I will watch the youtube video of the first weapon-system aimbot that never misses.
Post 10 Apr 2012, 19:33
View user's profile Send private message AIM Address Yahoo Messenger Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2139
Location: Estonia
Madis731 11 Apr 2012, 07:33
Yes, that is perfect, and it was already done (maybe not all the HTML5 stuff), but I was thinking more about the hardware in the server that will simulate the MMORPG. I think this needs to be pretty efficient. And I made a mistake. 256-bit wide AVX could handle 16x16-bit ops, but I don't know if every instruction has a WORD-capable variant (I know there are a lot of D & Q variants for floats). Maybe AVX2 will repair that Smile

EDIT: Forgot the link http://www.0x10co.de/


Last edited by Madis731 on 15 Apr 2012, 09:36; edited 1 time in total
Post 11 Apr 2012, 07:33
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger Reply with quote
r22



Joined: 27 Dec 2004
Posts: 805
r22 11 Apr 2012, 11:51
@Madis731 - I would of thought the CPU emulation would happen Client side and there would just be a client-server interface for API calls (I/O). Since, according to the little write-ups I've read the CPU only controls the player's ship (which I assume the player could control manually, it wouldn't make much sense for the server to take up that processing burden.

The only argument for server-side CPU emulation would be anti-cheat. But even in that case some sort of verification / signing could be done to mitigate it, without the need to emulate every client.

I don't see how SIMD would be helpful in emulating multiple CPUs at once. Since the instructions that would need to be emulated would be different, in essence losing the SI (single instruction) portion. But haven't thought about this topic to the extent you have...
Post 11 Apr 2012, 11:51
View user's profile Send private message AIM Address Yahoo Messenger Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2139
Location: Estonia
Madis731 11 Apr 2012, 12:41
Yes, that would become a problem (the SI part), extensive use of GATHER family (future AVX2) and alike must be very high latency. Even if brought to the client side, the 3 or 4 CPUs on board would likely be emulated on different cores/threads rather than in a single thread Sad

On the bright side, look what some people have made: http://t.co/JgYfil6t
Post 11 Apr 2012, 12:41
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.