Jump to content
ZackAttack

Designing a cartridge that supports 100% C/C++ game development

Recommended Posts

1+1 doesn't double the voltage; you just get 1. Ditto for 0+0=0, but bizarre things can happen when two active signals are present. 0+1 and 1+0 are examples of bus conflicts where the chips basically fight each other. One sinks current and one sources current so whichever chip wins can be unpredictable. This can lead to unintended consequences in games creating glitches or even crash the hardware, but generally the currents involved are low enough that the chips do not sustain actual damage. You cannot damage the hardware by loading bad software in other words.

 

I'm not sure that you cannot damage the hardware. Due to the way the 6507 is implemented it can sink far more current than it can source. When the 6507 outputs a logic 1 and the cart pulls it low the current is kept to a safe limit because of the relatively high resistance inside the 6507. I've personally grounded the entire data bus on my 2600 jr. and confirmed with a logic analyzer that it continues to operate just fine. (infinite loop of BRK instructions) Things are a little different when the 6507 outputs a logic 0 and the cart tries to pull it high. There is almost no resistance to ground and the cart hardware is likely a newer technology that has low resistance to +5V. The result can be close to short circuiting the +5V supply to ground. Multiply this by the 8 bit data bus and you have the potential to fry something. I can't speak for the Harmony's BUS driver implementation. It may or may not be possible to get the hardware in a state that will cause it to damage something. The design that I'm working on will use 7400 series ICs and pull up resistors to ensure that no matter what stupid mistakes you make programming the FPGA/MCU, it will be impossible to drive the bus high with anything other than a pull-up resistor. It adds a little bit to the total cost for each board, but I feel it's an acceptable trade off.

 

Okay, so let me see if I have this right:

 

The 6507 is instructed to STY $FF in an infinite loop.

 

At the same time, C code is running on an ARM core that is updating registers in memory based on how you've programmed your game.

 

The ARM is timed to copy the registers (bus stuff) to the data bus when it intercepts the STY command. It does this continually so the game never rolls or bounces.

 

The 6507 stores the Y register depending on what data was on the bus. Updating TIA and playfield and sprite information.

 

In this arrangement, the 6507 is really just a bus driver and the ARM does all the logic and memory manipulation. That's how you can program your game in C!

 

The Harmony cartridge implementation differs in that it stores a compiled binary in flash. It watches the address lines and then fetches data from a flash location and outputs that on the data bus. Sort of like a normal cartridge but with the benefits of not having to program an EPROM.

 

In this implementation, how do you get input information from the Atari RIOT? You can write data to the Atari, but how do you read joysticks and paddles?

There is a buffer of commands. Each command translates to a 6507 instruction + bus stuffing data. The buffer acts as a frame buffer. You write an entire frame worth of commands to the buffer and then instruct the system to use that buffer. There are at least two buffers to use. So the MCU can fill one buffer while the other one is used to render the screen by the FPGA. The MCU can take as much time to fill the next buffer. The FPGA will continue to render the active buffer until it is swapped for the other at the end of a frame. Really since the FPGA and MCU are both programmable there can be many variations on this implementation.

 

The Harmony cartridge implementation is called BUS. There are some other topics that discuss the details of that implementation. Basically the ARM MCU acts as a ROM emulator. The 6507 executes whatever code you assembled with the caveat that when in BUS mode a STY instruction will trigger the BUS driver. The BUS driver will then stuff in a different value depending on which TIA register is currently being addressed.

Share this post


Link to post
Share on other sites

In this implementation, how do you get input information from the Atari RIOT? You can write data to the Atari, but how do you read joysticks and paddles?

 

The cart has access to the address and data bus. Simply instruct the 6507 to read from the RIOT and watch what value the RIOT puts on the bus. I posted a video of this in action in an earlier post: http://atariage.com/forums/topic/238357-designing-a-cartridge-that-supports-100-cc-game-development/?p=3241026 Towards the end of the video you can see the 8 green LEDs reflected the value of SWCHA ($0280)

Share this post


Link to post
Share on other sites

 

 

There is a buffer of commands. Each command translates to a 6507 instruction + bus stuffing data.

 

Are these stored as binary machine language commands? So when you compile your C program, you'll need to translate any outgoing register into a machine language counterpart?

 

If I had say:

 

 

myPlayerSpriteX++;
myPlayerSpriteY++;

 

When compiled, it would have to know how to move sprite0 one right and one down. Moving sprites depends on where the Atari is on the scanline. That would be difficult!

 

Would it be easier to have a complete frame buffer where your C program changes the sprite locations, colors, and whatnot in memory, and then some other process that looks at the buffer and translates it to whatever scanline it is on. Or is that exactly how you described it? :)

Share this post


Link to post
Share on other sites

Apples to oranges, but those SNES-to-NES or -Gen adapters that don't even engage the CPU can still read the controller logic somehow. If you can "bus stuff" to push data through the Atari cart port, maybe you can "pull" off the RIOT and controller ports somehow. Maybe illegal opcodes will help.

 

Sans that, you feed instructions to the CPU to read the controller ports during the overscan period, and pump that data back to the cart bus anytime the TIA is not being used to update the display. Paddles might be difficult to pull off due to reading between scanlines, but joysticks would be easy.

Share this post


Link to post
Share on other sites

There's many ways to implement BUS Stuffing, these answers are specific to the driver we're currently developing for the Harmony/Melody.

I think it would be less confusing to everyone if you keep implementation details of Harmony/Melody/BUS in its own thread and link to it from everywhere else.

Share this post


Link to post
Share on other sites

There's many ways to implement BUS Stuffing, these answers are specific to the driver we're currently developing for the Harmony/Melody.

 

 

wallaby:

The 6507 is instructed to STY $FF in an infinite loop.

While it's possible to use STY $FF then stuff the address and the data, timing is difficult for 2+ bus stuffing events per instruction so we only stuff the data. As such, we still have to write the kernel in 6507 code. For the current build of Draconian the upper part of this display (above the green line):

 

 

Is created using this kernel:

ldx #0

...

stx

STUFFMODE ; 4 13 - turn on bus stuffing

 

ldy #$FF ; 2 15

sty VDELP0 ; 3 18

sty VDELBL ; 3 21

jmp VBentry ; 3 24

 

RealNormalKernel: ; - 20 43 ; 43 is latest to get here

sty Size ; 3 24 46 not used, read to keep stream in sync

R46color: ; - 46 ; 46 is latest to get here

sty Color ; 3 28 49 not used, read to keep stream in sync

R49: ; - 49 ; 49 is latest to get here

sty HMP0 ; 3 31 52 - no HMCLR needed as we are setting them all

sty HMP1 ; 3 34 55

sty HMM0 ; 3 37 58

sty HMM1 ; 3 40 61

sty HMBL ; 3 43 64

VBentry: ; - 64

R64: ; - 64 ; 64 is latest to get here

sty GRP0 ; 3 46 67 - VDELP0 on, so this is for next scanline

sty ENABL

; 3 49 70 - VDELBL on, so this is for next scanline

sty NextKernel ; 3 52 73

R73: ; - 73 ; 73 is latest to get here

sta WSYNC ; 3 55 76/0

R76: ; - 76/0

; at this point GRP0, ENABL and all HMxx values are loaded

sta HMOVE ; 3 3

sty GRP1 ; 3 6 - also updates GRP0 and ENABL due to VDELxx

sty ENAM0 ; 3 9

sty ENAM1 ; 3 12

jmp (NextKernel) ; 5 17

 

...

 

align 256 ; 17

NormalKernel: jmp RealNormalKernel ; 3 20

ExitKernel: jmp RealExitKernel ; 3 20

Resp0Strobe23: jmp RealResp0Strobe23 ; 3 20

Resp0Strobe28: jmp RealResp0Strobe28 ; 3 20

Resp0Strobe33: jmp RealResp0Strobe33 ; 3 20

 

...

 

RealResp0Strobe38: ; - 20

dec Sleep5 ; 5 25

RealResp0Strobe33: ; - 20

dec Sleep5 ; 5

25 30

RealResp0Strobe28: ; - 20

dec Sleep5 ; 5 25 30 35

RealResp0Strobe23: ; - 20

sta RESP0 ; 3 23 28 33 38

sty NUSIZ0 ; 3 26 31 36 41

sty COLUP0 ; 3 29 34 39 44

jmp R49 ; 3 32 37 42 47

 

...

The JumpDatastream is currently filled with 0 so every jmp (NextKernel) instruction will go to NormalKernel. The very last value in JumpDatastream is 3, so the final jmp (NextKernel) goes to ExitKernel which is when the green line is drawn. Eventually JumpDatastream will be filled with other values, such as 9 which would cause it to go to Resp0Strobe28, so player0 can be repositioned and reused. There will eventually be Resp1, Resm0, Resm1 and Resbl routines to reposition the other 4 moveable objects.

 

 

At the same time, C code is running on an ARM core that is updating registers in memory based on how you've programmed your game.

Before the kernel runs your custom C code has to prep a bunch of data and store it in datastreams. For the above, these are the datastreams:

 

 

;; Set this to adjust scanlines used for gameplay game area.

; The +5 is for 5 scanlines to reposition all objects,

; this will be consistantly 5 scanlines vs using PosObject which

; uses an additional scanline for each object that's on the

; right side of the screen

;DATASTREAM_SIZE = 160 + 5

 

 

JumpDataStream:

ds DATASTREAM_SIZE-1

ExitJumpDataStream:

ds 1

 

align 2 ; ARM accesses via unsigned short int (WORD)

GRP0_HMP0_DataStream:

 

ds DATASTREAM_SIZE*2

ds 2 ; Kernel done, turns off player0

 

align 2 ; ARM accesses via unsigned short int (WORD)

GRP1_HMP1_DataStream:

ds DATASTREAM_SIZE*2

ds 2 ; Kernel done, turns off player1

 

ENAM0_HMM0_DataSream: ; 0.5 increment. Upper nybble HMM0, bit 1 ENAM0

ds DATASTREAM_SIZE

ds 1 ; Kernel done, turns off missile 0

 

ENAM1_HMM1_DataSream: ; 0.5 increment. Upper nybble HMM1, bit 1 ENAM1

ds DATASTREAM_SIZE

ds 1 ; Kernel done, turns off missile 0

 

ENABL_HMBL_DataStream: ; 0.5 increment. Upper nybble HMM1, bit 1 ENAM1

ds DATASTREAM_SIZE

 

ds 1 ; Kernel done, turns off missile 0

 

Color_DataStream: ; new color of object being repositioned

ds DATASTREAM_SIZE

 

Size_DataStream: ; new size of object being repositioned

ds DATASTREAM_SIZE

The streams are laid out in the 6507 code in Display Data RAM. The 6507 code has a bunch of ECHO statements:

 

echo "// datastreams"

 

echo "#define DATASTREAM_SIZE ",[DATASTREAM_SIZE]d

echo "#define JUMP_DATASTREAM ",[JumpDataStream]d

...

 

That output this:

 

#define DATASTREAM_SIZE 165

#define

JUMP_DATASTREAM 8

...

 

That's copied over to the C code where it uses those defines to make pointers like this:

 

unsigned short int * const gPlayer0Datastream =(unsigned short int *)(DD_BASE + PLAYER0_DATASTREAM);

unsigned short int * const gPlayer1Datastream =(unsigned short int *)(DD_BASE + PLAYER1_DATASTREAM);

unsigned char * const gMissile0Datastream =(unsigned char *)(DD_BASE + MISSILE0_DATASTREAM);

unsigned char * const gMissile1Datastream =(unsigned char *)(DD_BASE + MISSILE1_DATASTREAM);

unsigned char * const gBallDatastream =(unsigned char *)(DD_BASE + BALL_DATASTREAM);

unsigned char * const gColorDatastream =(unsigned char *)(DD_BASE + COLOR_DATASTREAM);

unsigned char * const gSizeDatastream

=(unsigned char *)(DD_BASE + SIZE_DATASTREAM);

unsigned char * const gScoreDatastream =(unsigned char *)(DD_BASE + SCORE_DATASTREAM);

unsigned char * const gPlayfieldDatastream =(unsigned char *)(DD_BASE + PLAYFIELD_DATASTREAM);

 

The C code can update the datastream by setting values like gPlayer0Datastream[0] = 1, gPlayer0Datastream[10]=5, and so on. The routine that updates the datastream to create the above display is this:

 

 

void SetTestValues()

{

int i;

// first 5 are the reposition scanlines, not used for gameplay

for(i=0;i<5;i++)

{

gPlayer0Datastream = 0xff;

gPlayer1Datastream = 0xff;

gMissile0Datastream = 0x0f;

 

gMissile1Datastream = 0x0f;

gBallDatastream = 0x0f;

}

 

// gameplay area is 160 scanlines

for(i=5;i<DATASTREAM_SIZE;i++)

{

gPlayer0Datastream = i-5;

gPlayer1Datastream = i-5;

gMissile0Datastream = (i-5) & 0x0f;

gMissile1Datastream = (i-5) & 0x0f;

gBallDatastream = (i-5) & 0x0f;

}

}

 

The last thing your custom C code does is configure the BUS Stuffing Driver so it knows which of the 16 datatream is used for which TIA register(s). Yes, a single stream can be used by more than 1 register, it can also be used by RAM addresses. This is the C code which does that:

void SetDatastreams()

{

// ; 0 = pass and retrieve results from ARM VB

// ; 1 = GRP0 & HMP0

// ; 2 = GRP1 & HMP1

// ; 3 = ENAM0 & HMM0

// ; 4 = ENAM1 & HMM1

// ; 5 = ENABL & HMBL

// ; 6 = COLUPx for player being repositioned

// ; 7 = NUSIZx for player or missile being repositioned

// ; 8 = NextKernel datastream

 

// do a test to see if setPointer() is optimized away

QPTR[1] = PLAYER0_DATASTREAM << 20; // GRP0 & HMP0

QPTR[2] = PLAYER1_DATASTREAM << 20; // GRP1 & HMP1

QPTR[3] = MISSILE0_DATASTREAM << 20; // ENAM0 & HMM0

QPTR[4] = MISSILE1_DATASTREAM << 20; // ENAM1 & HMM1

QPTR[5] = BALL_DATASTREAM << 20; // ENABL & HMBL

QPTR[6] = COLOR_DATASTREAM << 20; // COLUP0, COLUP1 & COLUPF

 

QPTR[7] = SIZE_DATASTREAM << 20; // NUSIZ0 & NUSIZ1

QPTR[8] = JUMP_DATASTREAM << 20; // ZP RAM NextKernel

QPTR[9] = SCORE_DATASTREAM << 20; // Score/Radar/Lives/Formation display

 

 

 

// do a test to see if setMapping() is optimized away

QMAP[QUEUE_GRP0] = 0x11111111;

QMAP[QUEUE_HMP0] = 0x11111111;

QMAP[QUEUE_GRP1] = 0x22222222;

QMAP[QUEUE_HMP1] = 0x22222222;

QMAP[QUEUE_ENAM0] = 0x33333333;

QMAP[QUEUE_HMM0] = 0x33333333;

QMAP[QUEUE_ENAM1] = 0x44444444;

QMAP[QUEUE_HMM1] = 0x44444444;

QMAP[QUEUE_ENABL] = 0x55555555;

QMAP[QUEUE_HMBL] = 0x55555555;

QMAP[QUEUE_COLUP0] = 0x66666666;

QMAP[QUEUE_COLUP1] = 0x66666666;

QMAP[QUEUE_COLUPF] = 0x66666666;

QMAP = 0x66666666; //

ZP RAM 0x82

QMAP[QUEUE_NUSIZ0] = 0x77777777;

QMAP[QUEUE_NUSIZ1] = 0x77777777;

QMAP = 0x77777777; // ZP RAM 0x83

QMAP[NEXT_KERNEL & 0x3f] = 0x88888888; // ZP RAM 0x80

QMAP[QUEUE_PF0] = 0x99999999;

QMAP[QUEUE_PF1] = 0x99999999;

QMAP[QUEUE_PF2] = 0x99999999;

 

// do a test to see if setIncrement() is optimized away

QINC[0] = 0x100; // 1.0

QINC[1] = 0x100; // 1.0 GRP0 & HMP0

QINC[2] = 0x100; // 1.0 GRP1 & HMP1

QINC[3] = 0x80; // 0.5 ENAM0 & HMM0

QINC[4] = 0x80; // 0.5 ENAM1 & HMM1

QINC[5] = 0x80; // 0.5 ENABL & HMBL

QINC[6] = 0x100; // 1.0 COLUP0, COLUP1 & COLUPF

QINC[7] = 0x100; // 1.0 NUSIZ0 & NUSIZ1

QINC[8] = 0x100; // 1.0 NextKernel

QINC[9]

= 0x100; // 1.0 Score/Radar/Lives/Formation

}

 

The addresses are limited to $00-$24 for TIA and $80-$A4 for RAM.

 

 

When BUS Stuffing is turned on, the BUS Driver monitors for the STY zero page instructions. When it sees one it uses the values in QMAP to figure out which datastream to pull the data from. That data is then stuffed onto the bus at the appropriate time. Finally the datastream is advanced by the increment amount.

 

 

 

 

The ARM is timed to copy the registers (bus stuff) to the data bus when it intercepts the STY command. It does this continually so the game never rolls or bounces.

It only intercepts the STY command when BUS Stuffing is turned on. Once your kernel is done you turn it off:

 

ldx #$FF

stx STUFFMODE ; non-zero turns off bus stuffing

Then, like normal, the 6507 code takes care generating the sync signal at the appropriate time so the picture doesn't roll or bounce.

 

 

The 6507 stores the Y register depending on what data was on the bus. Updating TIA and playfield and sprite information.

The BUS Driver overrides the $FF value contained in the Y register when the 6507 goes to update the playfield (STY PF0, STY PF1, STY PF2) or sprite information (STY GRP0, STY COLUP0, STY NUSIZ0, etc).

 

 

In this arrangement, the 6507 is really just a bus driver and the ARM does all the logic and memory manipulation. That's how you can program your game in C!

The 6507 coordinates when and what to update. The ARM is the bus driver during the kernel. During overscan and vertical blank the 6507 will use the ARM as a co-processer for the game logic and memory manipulation, the ARM is not a bus driver during that time. This is just like your computer's CPU can offload calculations to your GPU. If your GPU is faster than your CPU at running certain routines then it makes sense to offload those routines to the GPU.

 

 

The Harmony cartridge implementation differs in that it stores a compiled binary in flash. It watches the address lines and then fetches data from a flash location and outputs that on the data bus. Sort of like a normal cartridge but with the benefits of not having to program an EPROM.

That's correct for the "ROM" emulation.

 

 

In this implementation, how do you get input information from the Atari RIOT? You can write data to the Atari, but how do you read joysticks and paddles?

The 6507 can write to the datastreams. In Draconian I have this datastream:

ARMsub: ds 1 ; Which ARM subroutine to run:

; 0 = Initialize()

; 1 = OverScan()

; 2 = VerticalBlank()

; 3 = SetDatastreams()

ARMswcha: ds 1 ; controller input to ARM

ARMswchb: ds 1 ; console switches to ARM

ARMinpt4: ds 1 ; left player firebutton

ARMinpt5: ds 1 ; right player firebutton

ARMvbtime: ds 1 ; time remaining in Vertical Blank

ARMostime: ds 1 ; time remaining in Overscan

ARMframe: ds 1 ; return value from call to OverScan

which is used like this for the joystick, console switches, etc:

; prep for call to OverScan()

ldx #>ARMsub ; 2 40

stx DS0PTR

ldx #<ARMsub ; 2 30

stx DS0PTR ; 4 34

ldx #RUN_OS ;

run = OverScan();

stx DS0WRITE ; 3

; pass the PIA and TIA registers to the ARM code

ldx SWCHA ; 4

stx DS0WRITE ; 4

ldx SWCHB ; 4

stx DS0WRITE ; 4

ldx INPT4 ; 3

stx DS0WRITE ; 4

ldx INPT5

stx DS0WRITE

ldx VBtime

stx DS0WRITE

ldx OStime

stx DS0WRITE

ldx #$FF

stx CALLFN ; tells the ARM code to run OverScan()

lda DS0DATA

sta Frame

Wow, that was quite a mouthful Spice... ;-)

 

I think it would be less confusing to everyone if you keep implementation details of Harmony/Melody/BUS in its own thread and link to it from everywhere else.

I think it may be useful info to some people so I reposted it. ;-)

  • Like 1

Share this post


Link to post
Share on other sites

Wow, that was quite a mouthful Spice... ;-)

:lol:

 

Bad part is that lost all the formatting, which makes it difficult to follow.

 

 

 

I think it may be useful info to some people so I reposted it. ;-)

I have it saved and will repost it, probably in the Bus Stuffing Demos topic. I was going to do so last night, but ended up going to bed early. I had a full weekend with family in town for the Houston Arcade Expo, followed by a late night Monday with friends to see Doctor Who: The Power of the Daleks at the theater. May or may not happen today as I'm still overtired.

  • Like 1

Share this post


Link to post
Share on other sites

While playing around with the API today I figured out a nice way to get a 13 colored playfield. I think with some refinement I can squeeze in 15Khz sampled audio and multiple single height colored players.

 

post-40226-0-54444700-1480212651_thumb.png

  • Like 3

Share this post


Link to post
Share on other sites

With 3-way venetian blinds and the 13 color PF it's possible to create a 38x64 colored background.

 

post-40226-0-79922700-1480696756_thumb.png

Edited by ZackAttack
  • Like 4

Share this post


Link to post
Share on other sites

I meant a timer in the arm mcu. The arm will be running off a much faster clock so it should have enough timer resolution to discern between pal and ntsc 6507 clock speeds. To make the measurement more accurate we could fill a command buffer with many write wsync commands and time how long it takes until the next irq is triggered. 100 wsync commands would be 7600 6507 cycles, that should make for a pretty big time difference between pal and nstc variants.

 

 

 

Success! I timed a full frame of 262 lines as that'll work well as part of an initial splash screen.

  • Like 1

Share this post


Link to post
Share on other sites

ZackAttack, any updates?

 

It's been a while since I've had time to work on this. The work that some of the other guys on here have been doing with the harmony cart uncovered an issue with bus-stuffing that would impact my design as well. Through some collaboration, several experiments, and the help of many AA members I've reached the following conclusions.

 

  1. Some systems can only be bus-stuffed with 0's forced onto the bus
  2. Some systems can only be bus-stuffed with 1's forced onto the bus
  3. Some systems can only be bus-stuffed with a specific combination of 0's and 1's forced onto the bus
  4. Some systems have very noisy address buses which makes it difficult to accurately read the next address in a timely manner.
  5. My proposed hardware design would not work on systems where one or more bits must be stuffed with a 1 instead of a 0

One of my biggest motivations for this project was to learn more about all the technologies involved and that has certainly been the case. The changes I would need to make to the hardware would make it so similar to the Harmony cart that it just wouldn't be worth the effort.

 

At this point designing a cartridge that supports 100% C/C++ game development is just a matter of building a new software suite for the Harmony hardware. This would include a brand new driver that operates much differently than what's out there now. I was able to put together a POC where the entire Atari game was written in ARM assembly. The biggest uncertainty right now is whether or not I'll find the time to continue working on this.

  • Like 1

Share this post


Link to post
Share on other sites

It's been a while since I've had time to work on this. The work that some of the other guys on here have been doing with the harmony cart uncovered an issue with bus-stuffing that would impact my design as well. Through some collaboration, several experiments, and the help of many AA members I've reached the following conclusions.

  • Some systems can only be bus-stuffed with 0's forced onto the bus
  • Some systems can only be bus-stuffed with 1's forced onto the bus
  • Some systems can only be bus-stuffed with a specific combination of 0's and 1's forced onto the bus
  • Some systems have very noisy address buses which makes it difficult to accurately read the next address in a timely manner.
  • My proposed hardware design would not work on systems where one or more bits must be stuffed with a 1 instead of a 0
One of my biggest motivations for this project was to learn more about all the technologies involved and that has certainly been the case. The changes I would need to make to the hardware would make it so similar to the Harmony cart that it just wouldn't be worth the effort.

 

At this point designing a cartridge that supports 100% C/C++ game development is just a matter of building a new software suite for the Harmony hardware. This would include a brand new driver that operates much differently than what's out there now. I was able to put together a POC where the entire Atari game was written in ARM assembly. The biggest uncertainty right now is whether or not I'll find the time to continue working on this.

 

Perhaps the game cartridge come with a toggle switch that states, "If A doesn't work, try B" and flip bits to 1 in the B position.

A9166546-A72E-967A-CCDE28B823A8E2B9.JPG

  • Like 1

Share this post


Link to post
Share on other sites

Regarding bus stuffing:

 

Is it still considered bus stuffing if your FPGA or CPLD or whatever outputs to the data bus?

 

For example, you have the VCS -> ROM. However, what if I wanted to intercept the ROM access and output a NOP (or whatever) instead from the FPGA? So instead of accessing the ROM for the instruction, the FPGA handles it? That's just a normal operation as far as the VCS is concerned?

 

The idea is that the VCS accesses the ROM like normal for most of its operation, but the FPGA takes over for some of that time. I'd like to avoid bus stuffing because of the difficulty ZackAttack mentioned above.

Share this post


Link to post
Share on other sites

The deciding factor is whether or not there is bus contention. Sounds like your plan is to use the pld as a proxy between the VCS and ROM. In that case you've created a new banking scheme that's more complex than most, but it's not bus stuffing and you shouldn't have to deal with any of the bus stuffing related issues I mentioned above.

Share this post


Link to post
Share on other sites

At this point designing a cartridge that supports 100% C/C++ game development is just a matter of building a new software suite for the Harmony hardware.

I'd prefer this route. No need to duplicate efforts and end up with something similar, and yet another standard.

Share this post


Link to post
Share on other sites
I'd prefer this route. No need to duplicate efforts and end up with something similar, and yet another standard.

 

The problem is only a few people can make a Harmony cartridge and I don't think the design is open source. I'd rather have other options even if they're re-inventing the wheel. At least you're not subject to a single person or small group of peoples' whim.

Edited by wallaby
  • Like 2

Share this post


Link to post
Share on other sites

 

The problem is only a few people can make a Harmony cartridge and I don't think the design is open source. I'd rather have other options even if they're re-inventing the wheel. At least you're not subject to a single person or small group of peoples' whim.

X2, it would be cool to see new hardware options for C++ programming! The portable Atari allows this too, that ARM version of Frogger is written in C++ but the API is exclusively Atari's like a high tech lockout chip.

 

imo new hardware options should follow the lead from the portable and allow enhanced video modes via component out from the cartridge. If it were possible to get the API and specs for the Atari portable, the new ARM games could even be made compatible.

 

One issue with additional ARM carts though is further fragmentation of the compatible console base on which the new games can run; I find Gip-Gip's Atac-C very interesting because his C games should be capable of running on the Harmony and other flash carts too.

Share this post


Link to post
Share on other sites

 

The problem is only a few people can make a Harmony cartridge and I don't think the design is open source. I'd rather have other options even if they're re-inventing the wheel. At least you're not subject to a single person or small group of peoples' whim.

Very true. I tried to buy Harmony cards or license the design awhile back and got no where. Would be great if someone came up with something that developers could use. I don't want to write a game that requires players to own a Harmony cartridge. I want my game to be in a standalone cartridge. It's really been very frustrating.

 

I'm willing to paid for prototype boards and/or a board run and give a number of boards to anyone who can make a Harmony clone...standalone, no loading lots of games. Or discuss other terms.

Edited by DanOliver

Share this post


Link to post
Share on other sites

Very true. I tried to buy Harmony cards or license the design awhile back and got no where. Would be great if someone came up with something that developers could use. I don't want to write a game that requires players to own a Harmony cartridge. I want my game to be in a standalone cartridge. It's really been very frustrating.

 

I'm willing to paid for prototype boards and/or a board run and give a number of boards to anyone who can make a Harmony clone...standalone, no loading lots of games. Or discuss other terms.

 

I'm only a novice with electronics, but I've made my own simple cartridge recently. I've also learned a lot from ZackAttack. It's too bad this cartridge design didn't pan out.

 

Although the Harmony is a proven design, I wouldn't want to clone it. It has some unusual limitations and I think a little bit of extra thought could bypass them. If you're looking for a standalone version of the Harmony - there is the Melody board. If you read their product page on it, it sounds like the perfect fit. Until you either A: try to get someone to make some or B: factor in the cost of the board. It is not a developer-friendly solution.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...