Baremetal tailgunner/commands


(regarding Another “cool” thing I tested (and it works!)…
I think we only need to synchronize the speed of the emulation while the “RAMP” signal is active (= zero).

The correct timing for the “normal” vectors is done by the VIA timer, and the correct timing for strings/raster is only
needed, when RAMP is active.

What this means…
The emulator (unhindered by waiting) runs at a full speed in the current version at a speed of about 160% of a vectrex.

That means, we can actually run the games (while not drawing) FASTER than on the real vectrex!
Since the 50Hz sync (WaitRecal) is still active the overall game speed is still 50Hz limited.

But games, which now run at 30Hz (since the vectrex is to slow to do all the calculation (e.g. rotations…, score keeping, conversions… etc)) can actually be sped up to reach 40Hz or even 50Hz. There is a noticable flicker reduction.

So with the emulation well in place – the original games will actually run BETTER than on a original vectrex!


The larger window of about 61MB for PiTrex programs cost me another 2-3 hours, since I forgot ONE location to put the new window in, and than I got exceptions while switching kernels…
Geee… I have to learn to concentrate more…
– Or I should only work on it on weekends – not after a days work…

Anyway – kernel switching including Linux is now working like a charm. If I find the time – tomorrow I’ll look at other things.

On my current „immediate“ todo list…. following things reside:
(in descending order)

- tailgunner with sound 
- elimination of T1 in vectrexInterface 
- "cleaner" vectors 
- exact sync in 
- speedup of 
- pitrex config files, for persistent settings 
- init a second cycle counter  
- asteroids with "external" roms 
- vectorbuffer system in vectrexInterface 
- "clue" system for printing in emulators 
  (so emulators can give hints which vectors to „collect“ and where to force 
  a zero ref…) 

It always comes something in the way.

Today I started out adding more sound stuff.Than I started with the vector pipeline…

… and what I finally did is some debug support.

I realized, that I need more „online” debugging/measurement capabilities in order to later improve the games.
For that I now included (via UART) a terminal – where you can enter commands and execute them while the game is running.
The command list structure is very easy:

 typedef struct {
 int id; 
 char *command; 
 char *commandShort;
 char *commandHelp;
 void (*commandHandler)(void);
} Command;

Command commandList[] =
 {1,"reset", "r", "reset | r -> reset to loader\r\n" ,  resetCommand },
 {1,"help",  "h", "help | h -> display all command\r\n" ,  helpCommand },
 {0,"", "",   "" ,  (void (*)(void)) 0 }
void helpCommand(void)
 // show help:
 int commandListCounter = 0;
 printf("List of API-Commands\r\n");
 while (commandList[commandListCounter].id != 0)
 commandListCounter = 0;
 printf("\r\nList of User-Commands\r\n");
 while (userCommandList[commandListCounter].id != 0)

void resetCommand(void)
  printf("Restarting kernel...\r\n");
  uint32_t progSapce = LOADER_START;
  void (*progStart)(void) = (void (*)(void))progSapce;

So you just have to fill out a new line in the „ commandList”, write the function – and you are all set to go.
Command line parsing is done… and the function called automatically. Up to five different parameters can be given, they are parsed and can be gotten via:

char *getCommandParameter(int parameterNo);

The parameters are given as text, but can be converted with:

int bm_atoi(getCommandParameter[0],10)

which converts the text to a number. Radix 10 is default – but the function also scans the text and automatically changes the radix:

string starting with „0″ -> octal
string starting with „%” -> binary
string starting with „0x” -> hex
string starting with „$” -> hex
string starting with „-” -> negative number
To use UART Terminal – pls enable „echo”, since it seems there is no „flush()” possible on the mini UART, so single characters are not transmitted (until a CR).

Also – there are „API”-Internal commands – which will always be present (if compiled in debug mode), and „user commands”.
User commands can be set from the „user games”.
As an example I added to the VecSim cluster (in vx_interface.c):

void gameCommand(void)
 printf("Atari Vector game simulator, Copyright 1993, 1996 Eric Smith\r\n");

Command vecSimCommandList[] =
 {1,"game", "g", "game | g -> display game information\r\n" ,  gameCommand },
 {0,"", "", "" ,  (void (*)(void)) 0 }
void init_graphics ( int p_smallwindow, int p_use_pixmap, int p_line_width, char *window_name)
  char *s;
  userCommandList = vecSimCommandList; 

Only as an example.
The user commands must be set after v_init();
The receiving and parsing is done in a single function:

void handleUARTInterface()

which is called from the v_waitRecal() function – but could also be called from anywhere else

So the next plan is to implement the pipeline – and than a „stop” command – which halts the emulation, but still displays the last „vectors” :-).

About sound…
As I say, I started with implementing sound effects to Tailgunner. For that I implemented to play the format AYFX (also used in Vide and in all my games, but the format was not invented by me).
For testing I did two effects… and used mainly the same code as in the Java example that Graham gave me.
SFX playing triggered from Tailgunner does work… but now we have..
a) find SFX (or create) that are close to the original
b) figure out which binary pattern in the sound FX belong to what event, as it seems that is somehow garbled.

Well, there are only 6 different events, shouldn’t be too hard.
Following does the syntax look like:

 unsigned char TailGunnerSFX_000[] = // EXPLODE - todo
{ 0xD0,   0x20};
unsigned char TailGunnerSFX_001[] = // THRUST
     0x7F,   0x10,   0x00,   0x00,   0x1F,   0x5F,   0x1C,   0x1F,   0x5F,   0x1E,
     0x1F,   0x1F,   0x1F,   0x5F,   0x1F,   0x1F,   0xD0,   0x20
unsigned char TailGunnerSFX_010[] = // LASER
    0xEA,   0xAB,   0x00,   0x00,   0xEA,   0x81,   0x00,   0x00,   0xA0,   0x61,
     0x00,   0xAA,   0xAB,   0x00,   0xA0,   0x81,   0x00,   0xAA,   0xAB,   0x00,
     0xAA,   0x81,   0x00,   0xAA,   0x61,   0x00,   0xAA,   0x49,   0x00,   0xAA,
     0x37,   0x00,   0xAA,   0x2A,   0x00,   0xAA,   0x20,   0x00,   0xAA,   0x18,
     0x00,   0x20,   0x00,   0x00,   0xD0,   0x20
unsigned char TailGunnerSFX_011[] = // SHIELD
{ 0xD0,   0x20};

unsigned char TailGunnerSFX_100[] = // BOUNCE nr. 7 is fake, sound_reg is 3, like shield
{ 0xD0,   0x20};

unsigned char TailGunnerSFX_101[] = // HYPERSPACE 
{ 0xD0,   0x20};
unsigned char TailGunnerSFX_110[] = // - not used
{ 0xD0,   0x20};
unsigned char TailGunnerSFX_111[] = // - not used
{ 0xD0,   0x20};

typedef struct {
 unsigned char *effectData; 
 int loop; 
 int channel; 
 int valid; 
} SoundEffect;

SoundEffect TailgunnerFX[] =
  {TailGunnerSFX_000, 0 ,0 ,1}, // EXPLODE
  {TailGunnerSFX_001, 1, 1 ,1}, // THRUST
  {TailGunnerSFX_010, 0, 0 ,1}, // LASER
  {TailGunnerSFX_011, 1, 2 ,1}, // SHIELD
  {TailGunnerSFX_100, 0, 0 ,1}, // BOUNCE
  {TailGunnerSFX_101, 0, 0 ,1}, // HYPERSPACE (end of wave warp)
  {TailGunnerSFX_110, 0, 0 ,0},
  {TailGunnerSFX_111, 0, 0 ,0},
int sound_reg[8];
int sound_reg_old[8];

  void update_sound (int strobe) 
   sound_reg[sound_addr] = sound_data;
   // Hack for shield bounce sound: bounce uses sound reg value 3 (like laser!)
   // bounce is assumed, if shield is on also (i.e. sound value 2)
   if ( (sound_reg[3] != 0) && (sound_reg_old[3] == 0) ) 
   if (sound_reg[2] != 0) 
   { // if shield is on,
   sound_reg[7] = 1;   //  set bounce on and
   sound_reg[3] = 0; //  set laser off
   sound_reg[7] = 0; // else set bounce off

   // process sound registers
   for (int i = 0; i < 8; i++) 
   if (TailgunnerFX[i].valid == 0)
   if ( (sound_reg[i] != 0) && (sound_reg_old[i] == 0) ) 
   v_playSFXCont(TailgunnerFX[i].effectData, TailgunnerFX[i].channel, TailgunnerFX[i].loop);
   if ( (sound_reg[i] == 0) && (sound_reg_old[i] != 0) ) 
     if (TailgunnerFX[i].loop)
   v_playSFXStop(TailgunnerFX[i].effectData, TailgunnerFX[i].channel);
   sound_reg_old[i] = sound_reg[i];


Today – as I was thinking about sound… I again thought about possible direct output from the Pi.
But it seems all „normal” ways are „blocked”.
I2S the headers are used…PWM the headers are used.
PWM might possibly be easiest and straight forward…

But it uses the same GPIO as the XXX signal.
Might the XXX signal be resettled? And to use PWN there is a tiny little piece of electronic needed. 4 capacitors, 4 resistors and an audio Jack.

If both – the XXX signal relocation and that circuit on board on the piTrex – than we had a viable vectrex independend audio output…. well dreaming… I guess the design is pretty final…

PWM – I am refering to:

Unused GPIO (Header) in PiTrex

   Port Assignments:
Descrip.|Bit    |Pin    |        GPIO
        |       |3      |            GPIO 2 (I2C SDA)
        |       |4      |             5V    
        |       |5      |            GPIO 3 (I2C SCL)
        |       |7      |            GPIO 4
        |       |8      |            GPIO 14 (UART 0 TXD)
        |       |10     |            GPIO 15 (UART 0 RXD)
        |       |14     |            GND
        |       |17     |            3V3
        |       |20     |            GND
        |       |25     |            GND
        |       |27     |            ID_SD (I2C ID eeprom)
        |       |28     |            ID_SD (I2C ID eeprom)
        |       |30     |            GND
        |       |34     |            GND
        |       |39     |            GND 

I have been thinking about the booting/developing again.

Now that I have the option on booting – my thoughts on this are following:

– have a menu entry (in the Vectrex) that show linux, if selected -> boot linux

– on start up examine:
  – if during startup any button of the vectrex controller is pressed -> boot raspbian
  – if piTrex board is not connected -> boot raspbian (whats the best way to check that?)

– serial terminal
I will implement a “terminal” mode, with that you will be able to send binaries to your connected Zero, which will be stored on the drive and will than be bootable. (there must be a linux/OS10/windows counterpart to send the stuff, commandline based, so it will be callable from a makefile)

I think with all these implemented we will do fine!

I did a little overall cleaning up…
But not finished…
But since Graham wanted a weekend „release” – here is my current stand.

The command line interface (UART) is working great….
you can change a few settings already…
Amongst others the WaitRecal frequency.
(Pressing button 1+4 also tells the current CPU usage in terms of WaitRecal percentage).
This shows Tailgunner needs at 76Hz about 110% of one round -> a little bit to slow for double speed…
But that might change, once we have the pipeline going. I didn’t do anything with that yet (further)…

Today I did a bid of bug hunting, cleanup and sound support for tailgunner. One „bug” still on the hunt is Karl Quappe under Vecx direct – that one is really strange…. stared 2 hours at it in disbelieve… and found nothing.

I think one of the very next things I do is to save settings to disk. I am getting tired of setting all things again, every time I look at a game :-).
Overall it looks much nicer :-).

Are we sure, that Battlezone emulation is 100% correct?
I have seen some disturbences which I can not explain. The second time the „battle zone“ scrolls up… the display is garbled for a few frames.

Also it generates sometimes:

*** Vector generator stack underflow! ***
*** Vector generator stack overflow! *** 

Also (after I left it alone for quite a few minutes) it crashed alltogether…

  • Some graphic glitches corrected
  • Landscape mode added (only via terminal / commandline)
  • Save settings implemented 🙂

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.