Homebrew – kotipolttoista kehitystä konsoleille ja kotitietokoneille

Artikkeli on julkaistu alun perin Skrollin numerossa 2013.2.

Omien ohjelmien ja pelien luonti menneiden konsoli- ja tietokonesukupolvien koneille on varmasti käynyt monen laitteita käyttäneen mielessä. Julkaisuajankohtanaan suljetut tai muuten vain huonosti dokumentoidut koneet pysyivät saavuttamattomissa monelle innokkaalle ohjelmointiharrastajalle vuosia tai jopa vuosikymmeniä.

Ohjelmien kehitys kodin tietokoneille ja konsoleille oli erityisesti kaupallisten pelikonsolien tapauksessa alustojen suljetun luonteen takia pitkään mahdotonta muille kuin kaupallisille peli- ja ohjelmistoyrityksille. Samalla kotitietokoneiden kasvaville markkinoille saapui avoimia tietokoneita, joille oli helposti saatavilla erilaisia ohjelmointityökaluja. Suljettujen laitteiden osalta ihmisiä yhdistävä internet mahdollisti kuitenkin vapaammaan tiedonvaihdon. Yhteisöllisyyden lisääntyessä harrastelijaryhmien toiminnassa myös vanhat konsolit ja tietokoneet saivat ensimmäiset tietopankkinsa. Näistä ammennettiin pohja emulaattorien ja kääntäjien, manuaalien ja tutoriaalien, ohjelmaesimerkkien ja työkaluohjelmien kehitykselle. Nämä tarpeelliset osat loivat pohjan ns. homebrew-liikkeelle, jossa nimensä mukaisesti kotipolttoista ohjelmistoa luodaan omin ehdoin.

Nykyaikainen ohjelmistokehitys on yhä enemmän kytköksissä vapaasti saataviin kehitystyökaluihin ja yleisiin standardeihin, jotka ovat kaikkien saatavilla ja hyödynnettävissä. Tämä nykypäivän itsestäänselvyys ei kuitenkaan päde suljettujen alustojen, kuten koti- ja käsikonsoleiden, tai muuten vain nykylaitteiden kanssa suoraan epäyhteensopivien, noin vuosikymmenen takaisten ja sitä vanhempien alustojen kohdalla.

Erityisesti konsoleiden valmistajat ovat perinteisesti kontrolloineet sitä, millaiset kehittäjät ovat saaneet mahdollisuuden käyttää sisäiseen käyttöön suunnattuja kehitystyökaluja ja tarpeellisia julkaisukoneistoja ohjelmien saattamiseksi markkinoille asti. Mutta miten onnistuu ohjelmien kehittäminen laitteille, joille ei ole saatavilla virallisia kehitystyökaluja? Entä jos laite yksinkertaisesti on jo sen verran vanha, ettei sille ole olemassa mitään alkuperäisen kehittäjän resursseja? Olisiko myös mahdollista käyttää myös korkeamman tason ohjelmointikieliä ohjelmistokehitykseen näille erittäin yleisille kotitietokoneille ja samantyyppisille pelikonsoleille?

Tämän artikkelin tarkoitus ei ole olla syväluotaava ”tee perässä” -opas. Pikemminkin se antaa tarvittavat ainekset lisätiedon hankintaan ja kattavan yleiskatsauksen homebrew-kehitykseen syventyen niihin osa-alueisiin, joissa vaaditaan erityisiä laitteisto- ja ohjelmistoratkaisuja.


PowerPak, CompactFlash-moduulisovitin Nintendo Entertainment Systemille.

Commodore 64 ja NES

Käsitellään ensimmäisinä esimerkkeinä kahta 8-bittiseen prosessoriarkkitehtuuriin perustuvaa suosittua kotikäyttöön tarkoitettua laitetta, Nintendo Entertainment Systemiä eli tutummin NESiä, ja Commodore 64 -kotitietokonetta. Kun lähtee selvittämään kehitystä tuntemattomalle alustalle, kannattaa aloittaa tunnistamalla sen oleellisimmat komponentit ja niiden ominaisuudet: prosessori, muistin määrä ja tyyppi, näytönohjain ja äänentoisto-ominaisuudet, tallennusmedia ja tiedonsiirto- ja syöttölaiteliitännät.


IDE4, ATA-/ATAPI-sovitin Commodore 64:lle.

 

Commodore 64

NES

Suoritinarkkitehtuuri

6502-yhteensopiva

6502-yhteensopiva

Muisti

RAM: 64 kilotavua (+laajennuksia -BASICin syömä pieni osuus)

RAM: 2 kilotavua (+kasettilaajennukset)

Näytönohjain

VIC-II – useita erilaisia näyttötiloja erilaisilla värimäärillä, 8 pikselin rautaskrollaus, rautaspritet

RP2C0? – pehmeä nelisuuntainen skrollaus riippuen asetuksista, rautaspritet, usean väripaletin tuki

Äänentoisto

SID – erittäin monipuolinen syntetisaattoripiiri joka mahdollistaa monimutkaisen ääniohjelmoinnin

APU 2A03 – viisi kanavaa, 7-bittinen äänisampletoisto

Tallennusmedia

C-kasetti ja 5¼ tuuman levyke. Lisäksi yleisesti saatavilla olevia moduuleja, joissa tallennusominaisuudet.

ROM-kasetit ja Famicom Disk System-levykeasema, lisäksi saatavilla massamuistilaitteilta ROM-tiedostoja lukevia FPGA-pohjaisia flashcartteja.

Tiedonsiirto ja syöttölaitteet

Useita standardoituja tiedonsiirtoliitäntöjä, Atari-standardin peliohjainliitännät

NES-peliohjainliitännät tai Famicomin konsolissa kiinni olevat ohjaimet. Saatavilla lisäksi CopyNES-kehityslaite joka mahdollistaa nopean tiedonsiirron.

Listaamalla molemmista alustoista ominaisuudet voidaan niistä rajata tarpeellisten työkalujen etsintä oleellisiin valintoihin.

Kääntäjä

Monesti koodin voi kääntää kohdelaitteessa, mutta yleensä kannattaa käyttää ns. ristiinkääntäjää, jota ajetaan suorituskykyisemmässä tietokoneessa. Tämä nopeuttaa kääntämistä ja helpottaa ohjelmakoodin testaamista ja virheiden etsintää, ja modernien käyttöjärjestelmien tarjoamat edut ovat käytettävissä. Siksipä sen sijaan, että ohjelmakoodi käännettäisiin kohdealustalla, se käännetäänkin toisella koneella ja käsitellään sitten kohdealustan ymmärtämään suoritettavaan tiedostomuotoon.

Dasm on pitkän kehityksen tulos ja yhä varsin käyttökelpoinen assembler-ohjelma. C64:lle erikoistunut Kick Assembler sisältää monimutkaiset makro-ohjelmointiominaisuudet ja kattavan apukirjaston funktioita datatiedostojen kuten äänen ja grafiikan käsittelyyn. Muita suosittuja 6502-ristiinkääntäjiä ovat ACME, XA65 ja C-kääntäjä CC65:n mukana tuleva CA65. 6502-suoritinta ohjelmoidaan yleensä joko suoraan 6502-assemblyllä tai sopivalla C-kääntäjällä.

Commodore 64 lataa ja suorittaa binääritiedostoja sellaisenaan alkaen osoitteesta, joka annetaan tiedoston kahdessa ensimmäisessä tavussa. NES-emulaattorit käyttävät usean eri standardin mukaisia ROM-moduulien kuvaustiedostoja, jotka sisältävät ohjelmakoodin ja -datan lisäksi tietoja moduulin lisäominaisuuksista kuten lisämuistin määrästä ja lisäpiireistä.

Lisäpiireillä sekä Nintendo että kolmannen osapuolen kehittäjät laajensivat NESin ominaisuuksia sen menestyttyä markkinoilla. Commodorelle taas oli saatavilla hyvin paljon erilaisia laitteen toimintaa laajentavia moduuleja ja oheislaitteita, ja se oli avoimena julkaisualustana ja sisäänrakennetulla BASIC-ohjelmointikielellä varustettuna erityisen suosittu valinta ensimmäiseksi kodin ohjelmointilaitteeksi.

Kääntäjän toiminta on hyvä tarkistaa emulaattorilla, joka on kohdelaitteen toimintaa jäljittelevä ohjelma. Yleensä nykyiset emulaattorit ovat riittävän tarkkoja simuloimaan koko laitteen toiminnot ja oheislaitteet, joten niitä kannattaa käyttää myös helppona testausvälineenä ohjelmalleen. Varoituksen sanana tosin se, että emulaattoreiden toiminta ei aina vastaa alkuperäisen laitteen toimintaa ja voi johtaa loogisten virheiden ja bugien analysoinnissa valheellisiin tunnistuksiin. Näin voi käydä, jos emulaattori on toteutettu naiivisti sivuuttaen tai oikoen alkuperäisen laitteiston toimintaprosessit, jotka monimutkaisuudessaan ovat haastavia jäljitellä virheettömästi. Täten emulaattoreihin ei voi luottaa ainoana testausympäristönä. Erityisesti analogisten artifaktien ja muiden teknisen suunnittelun kautta arvaamattomien konfiguraatioiden jäljittely digitaalisin menetelmin on vaikeaa esimerkiksi äänen tai kuvan tuotannossa.


C2N232, RS-232-liitännäinen kasettiasemasimulaattori.

Grafiikka- ja äänituotanto

Commodore 64:n ja NESin valinta esimerkeiksi ei ole mikään sattuma. Molemmat laitteet ovat äärimmäisen hyviä kehitysalustoja sekä niiden verrannallisen yksinkertaisuuden että monipuolisuuden takia. Kummallakin laitteella voidaan toistaa moniväristä grafiikkaa ja monikanavaista ääntä. C64 ei ole sidottu pelkästään yhteen kuvatarkkuuteen, ja NES voi skrollata pehmeästi neljän näytöllisen edestä grafiikkaa ruudulla. Molemmat laitteet tukevat myös spritejä, joilla voi rakentaa pelihahmoja ja muita liikkuvia kuvaelementtejä. Äänen tuotanto on molemmilla enimmäkseen oskillaattoreihin perustuvaa analogista piirisynteesiä.

Molemmille laitteille on olemassa useita erilaisia grafiikan ja äänen luomiseen ja muokkaamiseen erikoistuneita ohjelmia. Musiikin tekemiseen löytyy muun muassa NerdTracker II ja GoatTracker ja grafiikan käsittelyyn ja formaattimuunnoksiin YY-CHR ja ConGo. Näitä käyttämällä grafiikka- ja äänidatan käsittely ohjelmakoodissa jää vähäiseksi, jättäen monimutkaisten synteesi- ja grafiikkaominaisuuksien toteuttamisen näiden ohjelmien varaan. Kaiken voi myös tietenkin halutessaan käsitellä itse omin työkaluin alusta lähtien!

Kyseiset ohjelmat ovat nimenomaisesti ristiinkehitystyökaluja, joille vaihtoehtona toimivat myös kohdelaitteessa ajetut editorit. NESin tapauksessa sellaisia ei juuri ole, mutta Commodore 64:lle niitä löytyy enemmän kuin muille laitteille. Lisäksi joillekin grafiikkatiloille edelleen paras piirtomuoto on Commodorella ajettu ohjelma.

Grafiikan ja äänien ohjelmointi onnistuu parhaiten hyvän hakuteoksen kera. Commodoren tapauksessa koneen oma manuaali sisältää kaiken tarpeellisen tiedon muistiosoitteista ja näytönohjaimen ja äänipiirin ominaisuuksista. Kattavan näkemyksen laitteiston ominaisuuksista ja niiden tehokkaimmaista hyödyntämisestä saa lukemalla manuaaleja, muita hakuteoksia ja oppaita sekä erityisesti muiden tuottamaa lähdekoodia ja laitteelle soveltuvan algoritmiikan tutkimusta.

/* ESIMERKKIKOODIA COMMODORE 64:LLE – SKROLLIN TEKSTISKROLLERI
  KÄÄNTÄJÄ: DASM
*/
    processor 6502
    org    $1000
; näyttömuisti alkaa kohdasta $0400 (osoite heksadesimaaleina)
screen: EQU $0400
init:
   ldy #0
   sty scrollpos
; ruudun tyhjennys
   lda #$20
   ldx #0
clearscreen:
   sta screen,x
   sta screen+$0100,x
   sta screen+$0200,x
   sta screen+$0300,x
   dex
   bne clearscreen
mainloop:
   ; reunaefekti, $d020 on reunaväriosoite
   ldx #$4d
effect:
   asl $d020
   inc $d020
   dex
   cpx #15
   bne effect
; skrollataan vain joka 120. kerta mainloopissa
   inc scrollcounter
   lda scrollcounter
   cmp #120
   bne mainloop
   ldx #38
   ldy #0
   sty scrollcounter
   ; merkkien siirto ruudulla yksi merkki vasemmalle
scroll:
   lda screen+$0208+1,y
   sta screen+$0208,y
   iny
   dex
   bpl scroll
   ; uuden merkin syöttö oikealta
   ldx scrollpos
   lda scrolltext,x
   ; loppumerkki tekstissä, alkuun
   cmp #255
   beq init
   ; ASCII -> PETSCII
   sbc    #63
   sta screen+$0208+39
   ; seuraava merkki
   inc scrollpos
   jmp mainloop
scrollpos: DC 0
scrollcounter: DC 0
scrolltext:
   DC ”HEIPPA’MAAILMA””””””TERVEISET’SKROLLIN’LUKIJOILLE’JA’TRILOBITILLE’JA’PWPLLE”’PERINTEISEEN’TAPAAN’VOIT’VAIKKA’KERTOA’TERVEISET’KAIKILLE’SUOSIKKIASIOILLESI’KUTEN’ESIMERKIKSI’KISSOILLE’JA’POLKUVENEILLE”””””””””””””””””””””””””””””,255
; kääntö DASMilla: dasm scroll.asm -o scroll.prg   
; ohjelman suoritus Commodore 64 BASIC-kehotteesta: SYS 4096


1541 Ultimate Plus, FPGA-pohjainen levyasema- ja moduulisimulaattori Commodore 64:lle.

Suoritus

Assemblerin tuottama prg-tiedosto voidaan suorittaa sellaisenaan Commodore 64:llä monella eri tapaa. Tässä muutama, joka soveltuu myös useille erilaisille saman aikakauden kotitietokoneille:

  • Ohjelmabinääritiedosto voidaan muuntaa ääneksi, joka tallennetaan kasetille ja ladataan siltä.
  • Ohjelma tallennetaan levykkeelle joko käyttäen PC-yhteensopivaa levykelukijaa tai -yhteyskaapelia (esimerkiksi Star Commander ja X1541-kaapeli).
  • Ohjelma ladataan suoraan muistiin esimerkiksi C2N232:ta käyttäen.
  • Modeemi- tai nollamodeemikaapelisiirto.
  • NESillä ROM-kuvatiedoston suorittaminen vaatii ROM-moduulien toimintaa jäljittelevän kehityslaitteen, joka simuloi FPGA-piirillä moduulien erikoispiirejä. Laite lukee tiedostot esimerkiksi SD- tai MMC-muistikortilta. Tälläinen flashcart on mm. NES PowerPak.

Toinen suosittu tapa on ns. repropakin valmistaminen. Tässä menetelmässä samantyyppisen laitteiston sisältävän pelimoduulin ROM-piirit vaihdetaan itse kirjoitettuihin piireihin, jotka sisältävät oman ohjelman grafiikat ja ohjelmakoodin omilla piireillään. Tämä vaatii kuitenkin jo sen verran elektroniikkaosaamista, että flashcartin hankinta hinnasta huolimatta tekee tästä vaiheesta NESin ohjelmistokehitystä huomattavasti helpompaa.

Esimerkkiohjelmamme NESille on tehty käyttäen suosittua 6502-prosessorille tarkoitettua C-kielen ristiinkääntäjää cc65, joka on saatavilla usealle eri modernille käyttöjärjestelmälle. NES-kehitystä helpottaa huomattavasti neslib-kirjasto, joka tarjoaa loogisesti nimetyn ja jäsennellyn rajapinnan NESin muistiin ja laitteistoon. Paketista löytyy myös monipuolisempia ohjelmaesimerkkejä.

// NES-koodiesimerkki: tekstiä ruutuun käyttäen taustagrafiikkamerkkejä.
// mukautettu shirun esimerkistä.
// Tämä esimerkki olettaa, että fontin merkit ovat ASCII-järjestyksessä
// taustagrafiikan tämänhetkisessä merkkisivussa (nametable) kohdissa $00-$3f
#include ”neslib.h” // NESLIB mukaan
// makro nametable-osoitteen määrittämiseksi
#define NTADR(x,y) ((0x2000|((y)<<5)|x))
// funktio: kirjoita merkkijono str näyttömuistiin kohtaan adr
void put_str(unsigned int adr,const char *str)
{
   vram_adr(adr);
   while(1)
   {
      if(!*str) break;
      vram_put((*str++)-0x20); // -0x20 = ASCII-koodista merkin numeroksi
   }
}
void main(void)
{
   pal_col(1,0×30); // asetetaan tekstin väri
   put_str(NTADR(2,2),”HEI KAIKKI SKROLLIN LUKIJAT”);
   ppu_on_all(); // näytönpiirto päälle
   while(1); // ikiluuppi
}

Suljetun avaaminen avoimin työkaluin – Dreamcast

Massamuisti

Samaa lähestymistapaa ohjelmien kehittämiseen voidaan käyttää myös uudemmalla kotikonsolilla, jolle pääsy on ollut suljettu kotikehittäjiltä suurimman osan konsolin elinajasta markkinoilla. Esimerkkimme on Segan Dreamcast-konsoli sen CD-formaatin hankintahelppouden ja laitteen grafiikkaominaisuuksien ja kehitystyökalujen nykyisen saatavuuden takia. Dreamcastin GD-ROM-standardi ei estä mitenkään tavanomaisten poltettujen CD-R-levyjen käyttöä omien ohjelmien säilyttämiseen, kunhan konsoli on vain joko ensin modifioitu lukemaan poltettuja levyjä tai käynnistetty käyttäen erityistä käynnistyslevyä, joka mahdollistaa poltettujen levyjen käytön ohjelmien lataukseen. Yksi suosituimmista on Utopia bootdisk.

Avoimien työkalujen hyödyntäminen

Dreamcastille ohjelmien kehittäminen on helppoa, sillä sen SH4-prosessorille voi kääntää C-kielistä koodia suositulla GNU C-kääntäjällä, gcc:llä. Koska Dreamcastin grafiikka- ja ääniominaisuudet ovat huomattavasti monimutkaisemmat kuin 8-bittisillä konsoleilla, on myös apukirjastojen käyttäminen nopean ohjelmistokehitys- ja testausprosessin helpottamiseksi korkean tason ohjelmointikielen kanssa mahdollinen valinta. Suosittu kaupallisissakin julkaisuissa käytetty vaihtoehto on KallistiOS, joka tarjoaa käyttöjärjestelmäpalveluita ja muita multimediaominaisuuksien ja syötetiedon käsittelyyn soveltuvia kirjastokokonaisuuksia. KallistiOS:llä voidaan kehittää ohjelmia myös Gameboy Advance ja PlayStation 2 -pelikonsoleille.

Grafiikan piirtämiseen voidaan käyttää OpenGL-grafiikkakirjastoa, joka on yhä nykyäänkin suosittu erityisesti siirrettävien eli helposti monelle alustalle käännettävien ohjelmien kehittämisessä. Tässä mielessä Dreamcast-ohjelmien kehittäminen ei merkittävästi eroa nykyisille laitteille kehittämisestä kuin suoritustehonsa ja joidenkin erityisominaisuuksiensa osalta. Dreamcastin etuna on se, että jokainen konsoli on täysin identtinen, ja siten sama ohjelma toimii varmasti jokaisella konsolilla samalla tavalla, lukuunottamatta televisiojärjestelmien virkistystaajuuksien eroavaisuuksia.

Yleiskatsauksena siis kaikki tarvittavat ohjelma- ja laitteisto-osat ovat ilmaisia, helposti saatavilla ja standardinmukaisia, vaikka laitteelle kehittäminen ei ”laillisia” teitä käyttäen olekaan mahdollista. Lopullinen käännetty ohjelma syötetiedostoineen tarvitsee vain kirjoittaa ISO-standardin mukaiseen CD-levykuvaan, polttaa fyysiselle levylle sopivin ohjein ja käynnistää modifioidulla tai käynnistyslevyllä varustetulla konsolilla.

Dreamcastille kehittäminen ei ole merkittävästi erilaista kuin nykytietokoneille. On kuitenkin syytä muistaa, että konsoleiden suunnitteluratkaisuista johtuen kaikki ohjelmat, jotka toimisivat moitteettomasti nykytietokoneilla, eivät kuitenkaan toimi Dreamcastillä laitteen huomattavasti pienemmän suoritustehon vuoksi. Laitteen rautaominaisuuksien tehokas hyödyntäminen vaatii yrityksen ja erehdyksen mukanaan tuomaa kokemusta, tietolähteistä lisäsisältöä ammentaen.

// KallistiOS-esimerkkiohjelma. Ei juuri eroa perinteisestä C-esimerkistä.
#include <kos.h>
// Oletusasetukset käynnistettäessä
KOS_INIT_FLAGS(INIT_DEFAULT);
int main(int argc, char **argv) {
    printf(”\nTerkut konsolistasi!\n\n”);
    return 0;
}

Ristiinkehitys vaatii omanlaistaan tutkimusmatkailuhenkeä, sillä saatavilla ei yleensä ole nykylaitteiden laajamittaista tieto- ja tukiverkostoa. Osittain tästä syystä monet vanhat laitteet synnyttävätkin ympärilleen omia harrastelijaryhmiään ja -yhteisöjään. Juuri näistä paras tietämys koneiden syvälliseen sielunelämään usein löytyykin. Tutkimaton potentiaali piilee laitteissa, jotka vasta nyt ovat helposti avattavissa kehitysalustoiksi. Toisaalta vanhoista läpikotaisin tongituista ohjelmoijien suosikkikoneista voi löytyä monia yllättäviä aarteita. Jokainen uusi vuosi tuo tullessaan ennalta arvaamattomilla tavoilla rajoja rikkovia ohjelmia laitteisiin, jotka moni on jo jättänyt menneisyyteen.

Lisätietoja: http://www.elliptique.net/wiki/doku.php?id=dreamcast

Teksti: Visa-Valtteri Pimiä
Kuvat: Visa-Valtteri Pimiä, Marko Mäkelä, Wikipedia Commons