New game uploaded: Core War

All aspects of programming on the Commander X16.
rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

New game uploaded: Core War

Post by rje »



1 hour ago, svenvandevelde said:




What is a CLI?



Sorry about that -- yeah a "command line".

I have to do the hard work and get the opcodes all working properly... then I can put the arena / core into banked RAM.

rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

New game uploaded: Core War

Post by rje »


So I'll ask for the sake of asking.  What's the best use for that banked RAM?

I'm just assuming that the "arena" is the best place for it, because that way I can have enough memory for an 8000 location arena, which will need 40k to 48k RAM, depending on what the location record stores.

The downside is that fetching data from the arena becomes a function call, or a macro, instead of directly accessing an array.  I mean, array access is WONDERFUL and easy.  

But... suppose I only need the current 16K RAM for the 4K arena.  Maybe I can get by with that... I still have 6K "golden RAM" free, and I can shove things like the help text (for example) into a single RAM bank.

I'm just asking for the sake of asking.  I always feel the need to use up all that free RAM, but that doesn't mean I ought to.

Ed Minchau
Posts: 508
Joined: Sat Jul 11, 2020 3:30 pm

New game uploaded: Core War

Post by Ed Minchau »



1 hour ago, rje said:




So I'll ask for the sake of asking.  What's the best use for that banked RAM?



I'm just assuming that the "arena" is the best place for it, because that way I can have enough memory for an 8000 location arena, which will need 40k to 48k RAM, depending on what the location record stores.



The downside is that fetching data from the arena becomes a function call, or a macro, instead of directly accessing an array.  I mean, array access is WONDERFUL and easy.  



But... suppose I only need the current 16K RAM for the 4K arena.  Maybe I can get by with that... I still have 6K "golden RAM" free, and I can shove things like the help text (for example) into a single RAM bank.



I'm just asking for the sake of asking.  I always feel the need to use up all that free RAM, but that doesn't mean I ought to.



Well, you don't have 6k of Golden RAM, you have 1kb.

Why would an arena cell need more than one byte? The original core war only had something like 10 instructions. 

BruceMcF
Posts: 1336
Joined: Fri Jul 03, 2020 4:27 am

New game uploaded: Core War

Post by BruceMcF »



7 hours ago, rje said:




So I'll ask for the sake of asking.  What's the best use for that banked RAM?



I'm just assuming that the "arena" is the best place for it, because that way I can have enough memory for an 8000 location arena, which will need 40k to 48k RAM, depending on what the location record stores.



The downside is that fetching data from the arena becomes a function call, or a macro, instead of directly accessing an array.  I mean, array access is WONDERFUL and easy.  



But... suppose I only need the current 16K RAM for the 4K arena.  Maybe I can get by with that... I still have 6K "golden RAM" free, and I can shove things like the help text (for example) into a single RAM bank.



I'm just asking for the sake of asking.  I always feel the need to use up all that free RAM, but that doesn't mean I ought to.



If the highest frequency operations fit in under 8K, there's a lot to like for using Banked RAM for the VM itself. If an arena plus the other global transient data that fits into LowRAM, then calling across segments might require doubling the JSR/RTS, but if that is in the ">80% of the code that takes <20% of the cycles", that could be an acceptable overhead for clearing the LowRAM for the arena matrix.

Calls pass information in given locations rather than registers, but when you are defining the calls rather than integrating already-defined standard call, you just design with that in mind. Then at the very end of each CODE segment, you have:


Quote




LONGCALL: LDA RAMBANK : PHA : STY RAMBANK : JSR + : PLA : STA RAMBANK : RTS

+ JMP ($BF00,X)



and you have the banks of your different code banks in zero page, and to make a long call to the "Showit" routine in "HelpBank" (to invent gadget/widget names):

LDY HELPBANK : LDX #SHOWIT : JSR LONGCALL

In that process, in the third instruction of the longcall you have started executing the version of the longcall in the destination bank, and you execute the RTS from the version of the longcall in the caller segment.

And if your "CORE" process fits entirely within a segment and the called routines are lower frequency or I/O functions, so that you do not need a symmetric call, but you have one caller segment and one or more called segments, you can dispense with saving the current bank:



LONGCALL: STY RAMBANK : JSR + : LDA COREBANK : STA RAMBANK : RTS

+ JMP ($BF00,X)



In that process, your caller don't ever execute some of these instructions and your called don't ever execute some, but you still assemble parallel routines for sanity's sake, because it ensures that the locations are correct when the segment changes.



 

rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

New game uploaded: Core War

Post by rje »


Thank you Bruce!  I appreciate the suggestions... and yeah, I have thought about how nice it would be to shove some common operations into assembly into a bank.  I'm going to keep that in mind.  It's a good idea, since I can start easy and small.

I considered that 8K of static data and routines leveraged into Bank 1 wouldn't require any overhead.  And that might be all I need.  Maybe.

Re "golden" RAM.  Sorry, I meant main RAM.  I've got 32K of it filled up, half with the arena.  6K left to cram in the "multi-processing" orchestration.  Doable, probably not a problem, but still.



 

@Ed: Regarding opcodes.  The instruction is 32 bits...  More if the arena is > 4096 locations.   There are only 15 opcodes, but there are two operands, each with four possible addressing modes.  

unsigned char opcode: 4;
unsigned char aMode: 2;   // immediate, direct, indirect, predecrement indirect
unsigned char bMode: 2;   // same modes as above
unsigned char A: 12;  // i.e. the size of the arena
unsigned char B: 12;  // again, arena size
// = 32 bits.

//
// If the arena size grows to, say, 8000 locations, then:
//
unsigned char opcode: 4;
unsigned char aMode: 2;   // immediate, direct, indirect, predecrement indirect
unsigned char bMode: 2;   // same modes as above
unsigned char A: 13;   // i.e. the size of the arena
unsigned char B: 13;  // arena size
// = 34 bits... e.g. 5 bytes.

4096 locations is really not bad for an 8-bit arena...  I believe 8000 locations became normal in the 1990s, so let's say 12 bits is OK.

Some simulators have an additional "owner" byte.  Suffice to say that 4 bytes is a minimum "cell" size, without doing memory management.

rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

New game uploaded: Core War

Post by rje »


So I've recently re-read articles and postings and webpages on Core War, and after internal debating I'm preferring these assumptions:


  • Based on 1986 opcodes and modes.


  • Portable, simplistic file format.


  • Core size is 4096 cells.


  • Up to 8 warriors, each with up to 8 processes.


Redcode files have a minimal format that allows portability and bare functionality:

X1A #nnn #nnn
X1B #nnn nnn
X1C #nnn @nnn
X2A nnn #nnn
X2B nnn nnn
X2C nnn @nnn
X3A @nnn #nnn
X3B @nnn nnn
X3C @nnn @nnn

So each valid line has three "words": 


  1. Ocode, which can be any length, but currently they're all 3 characters long.


  2. Operand A, which has an optional sigil denoting immediate (#) and indirect-address (@) modes. 


    1. No sigil means direct-address mode.


    2. The rest of the operand is a positive or negative number.




  3. Operand B (same format as A).


Everything that doesn't scan is a comment.  I may have to tighten that up a bit!

The loader doesn't do pre-processing.  So I don't have macro support, I don't have pseudo-opcode support, and I don't have label support.  Maybe later.  Of course an off-board pre-processor would work just fine.

*1 Opcodes and Modes.  I'm using the original 3 modes. These are the opcodes I like currently:

0 HCF

(Used for holding data; remove the process from the system ("Halt and Catch Fire"))

1 MOV
2 ADD
3 SUB

(Funnily enough, it turns out that SUB is not simply a negated ADD. 
I was sad when I figured this out.)

4 JMP: unconditional jump
5 JMN: jump if A != 0
6 JMZ: jump if A == 0

7 SEQ: ++ip if A == B ("CMP" = skip if equal)
8 SLT: ++ip if A < B (skip if less than)
9 SNE: ++ip if A != B
10 FLP: ++ip if an essentially random system status word < B

11 reserved
12 reserved
13 reserved

14 XCH: exchange operands
15 SPL: push to process queue

 

 

 

 

BruceMcF
Posts: 1336
Joined: Fri Jul 03, 2020 4:27 am

New game uploaded: Core War

Post by BruceMcF »


Yeah, you can get there incrementally, and if it is all called routines in banks, with the calller in LowRAM, all you NEED is zeropage locations to store the bank addresses if you spill over 8k support routines. A parser and help routines makes great examples of the kind of thing that can be put there.

But if the caller is in LowRAM, it's still just

"LDY HELPBANK : STY RAMBANK : JSR routine"

... which you could easily make a ".JBSR bank,address" macro (for jump bank subroutine). The only thing to keep in mind when still in just one bank is to leave on register free for a later bank select operation if/when it spills into two.

rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

New game uploaded: Core War

Post by rje »


LABELS

I am always thinking about labels.  Labels are critically important in writing and reading Redcode.  For awhile I figured they could be managed off-board with a pre-processor.  But, I am not convinced, though I CAN totally defer writing that parsing logic in until I can't stand it any longer.

I think it's going to be a two-pass effort:

Parse each line of code, building up a dictionary of labels and their corresponding line numbers.  In other words, something like

char* label[ MAX_NO_OF_LINES ];

Then substitute in the second pass.

I can get away with this because redcode programs are short.  In my case, probably to 256 instructions max.

 

Traditional redcode doesn't have any special characters to denote a label: it just shows up before the opcode.  Thus a dumb sscanf might just look for it first, e.g.


if (sscanf(input, "%s %s %s %s", label, opcode, a, b) != 4)


Since I'm already validating the opcode, if it checks out then good-faith suggests that <label> really is a label.

 

 

rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

New game uploaded: Core War

Post by rje »


I've added a label for building with CC65 versus CC, and added a Makefile.cc.  So now I can run it on my Mac as I work out the kinks.

 

rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

New game uploaded: Core War

Post by rje »


Okay, I've got the arena running, and I believe the opcodes work correctly ?

Up to eight warriors can run in the arena at the same time, and each can split into eight processes maximum.  I haven't tried the stress test yet...

I added in one more opcode that's been there (in some form) from the very beginning.  That brings the total to 13:


  1. HCF (halt and catch fire -- holds data and kills any process that tries to execute it)


  2. MOV


  3. ADD


  4. SUB


  5. JMP


  6. JMN


  7. JMZ


  8. SEQ


  9. SLT


  10. SNE


  11. FLP - an experimental and marginally useless opcode I might remove.


  12. DJN - I resisted adding this for a long time


  13. XCH


  14. SPL


Room for two more.  Useless but amusing opcodes are welcome.

I removed the more annoying addressing mode: "indirect address with pre-decrement".  Awful.  I'm open to suggestions for amusing but not complicated or annoying addressing modes.  Maybe an indexed mode? 

 

Post Reply