Lots of changes. Maybe for the better, maybe not.

This commit is contained in:
Jens ]dne Rydland 2008-11-28 21:50:56 +00:00
parent aaee3363c4
commit fc0606303b
20 changed files with 966 additions and 72 deletions

View File

@ -2,5 +2,21 @@
all: ay8910test
ay8910test: ay8910.c
gcc -o ay8910test ay8910.c
ay8910test: ay8910.o sound.o sndintrf.o
gcc -o ay8910test sound.o ay8910.o sndintrf.o -lSDL
ay8910.o: ay8910.c
gcc -c -Wall ay8910.c
sound.o: sound.c
gcc -c -Wall sound.c
#streams.o: streams.c
# gcc -c -Wall streams.c
sndintrf.o: sndintrf.c
gcc -c -Wall sndintrf.c
.PHONY clean:
rm ay8910test *.o

View File

@ -61,9 +61,9 @@
| |
GND GND
Each Volume level x will select a different resistor Rx. Measurements from fpgaarcade.com
where used to calibrate channel mixing for the YM2149. This was done using
a least square approach using a fixed RL of 1K Ohm.
Each Volume level x will select a different resistor Rx. Measurements from
fpgaarcade.com were used to calibrate channel mixing for the YM2149. This was
done using a least square approach using a fixed RL of 1K Ohm.
For the AY measurements cited in e.g. openmsx as "Hacker Kay" for a single
channel were taken. These were normalized to 0 ... 65535 and consequently
@ -73,14 +73,13 @@ line e.g. with the formula used by pcmenc for the volume: vol(i) = exp(i/2-7.5).
The following is documentation from the code moved here and amended to reflect
the changes done:
Careful studies of the chip output prove that the chip counts up from 0
until the counter becomes greater or equal to the period. This is an
important difference when the program is rapidly changing the period to
modulate the sound. This is worthwhile noting, since the datasheets
say, that the chip counts down.
Also, note that period = 0 is the same as period = 1. This is mentioned
in the YM2203 data sheets. However, this does NOT apply to the Envelope
period. In that case, period = 0 is half as period = 1.
Careful studies of the chip output prove that the chip counts up from 0 until
the counter becomes greater or equal to the period. This is an important
difference when the program is rapidly changing the period to modulate the
sound. This is worthwhile noting, since the datasheets say, that the chip
counts down. Also, note that period = 0 is the same as period = 1. This is
mentioned in the YM2203 data sheets. However, this does NOT apply to the
Envelope period. In that case, period = 0 is half as period = 1.
Envelope shapes:
C AtAlH
@ -99,20 +98,35 @@ The envelope counter on the AY-3-8910 has 16 steps. On the YM2149 it
has twice the steps, happening twice as fast.
***************************************************************************/
#include <SDL/SDL.h>
#include <unistd.h>
#include <math.h>
// MAME headers
/*
#include "osdcomm.h"
#include "mamecore.h"
#include "deprecat.h"
#include "sndintrf.h"
#include "deprecat.h"
//#include "deprecat.h"
#include "streams.h"
//#include "cpuintrf.h"
#include "cpuintrf.h"
*/
#include "sndint.h"
#include "ay8910.h"
// lazyness
#define logerror printf
/* pen_t is used to represent pixel values in bitmaps */
typedef UINT32 pen_t;
/* stream_sample_t is used to represent a single sample in a sound stream */
typedef INT32 stream_sample_t;
/*************************************
*
* Defines
*
*************************************/
#define MAX_OUTPUT 0x7fff
@ -145,8 +159,19 @@ has twice the steps, happening twice as fast.
#define TONE_ENVELOPE(_psg, _chan) (((_psg)->regs[AY_AVOL + (_chan)] >> 4) & 1)
#define ENVELOPE_PERIOD(_psg) (((_psg)->regs[AY_EFINE] | ((_psg)->regs[AY_ECOARSE]<<8)))
/*************************************
*
// prototypes
extern int sdl_init(int samplerate);
extern int sdlaudio_init(int samplerate);
extern void sdl_kill();
extern int sdl_create_buffers(void);
extern void sdl_destroy_buffers(void);
extern void sdl_cleanup_audio(int samplerate);
extern void sdl_callback(void *userdata, Uint8 *stream, int len);
extern void osd_update_audio_stream(int samplerate, INT16 *b, int s);
/**************************************
* Type definitions
*
*************************************/
@ -166,7 +191,7 @@ struct _ay8910_context
int index;
int streams;
int ready;
sound_stream *channel;
//sound_stream *channel;
const ay8910_interface *intf;
INT32 register_latch;
UINT8 regs[16];
@ -216,7 +241,7 @@ static const ay_ym_param ym2149_param_env =
1397, 1123, 925, 762, 578, 438, 332, 251 },
};
#if 0
#if 1
/* RL = 1000, Hacker Kay normalized, 2.1V to 3.2V */
static const ay_ym_param ay8910_param =
{
@ -270,6 +295,7 @@ static const ay_ym_param ay8910_param =
*
*************************************/
INLINE void build_3D_table(double rl, const ay_ym_param *par, const ay_ym_param *par_env, int normalize, double factor, int zero_is_off, INT32 *tab)
{
int j, j1, j2, j3, e, indx;
@ -393,8 +419,7 @@ static void ay8910_write_reg(ay8910_context *psg, int r, int v)
//if (r >= 11 && r <= 13 ) printf("%d %x %02x\n", PSG->index, r, v);
psg->regs[r] = v;
switch( r )
{
switch ( r ) {
case AY_AFINE:
case AY_ACOARSE:
case AY_BFINE:
@ -608,8 +633,8 @@ static void ay8910_update(void *param,stream_sample_t **inputs, stream_sample_t
static void build_mixer_table(ay8910_context *psg)
{
int normalize = 0;
int chan;
int normalize = 0;
int chan;
if ((psg->intf->flags & AY8910_LEGACY_OUTPUT) != 0)
{
@ -628,7 +653,7 @@ static void build_mixer_table(ay8910_context *psg)
*/
build_3D_table(psg->intf->res_load[0], psg->par, psg->par_env, normalize, 3, psg->zero_is_off, psg->vol3d_table);
}
/*
static void ay8910_statesave(ay8910_context *psg, int sndindex)
{
state_save_register_item("AY8910", sndindex, psg->register_latch);
@ -651,7 +676,7 @@ static void ay8910_statesave(ay8910_context *psg, int sndindex)
state_save_register_item("AY8910", sndindex, psg->holding);
state_save_register_item("AY8910", sndindex, psg->rng);
}
*/
/*************************************
*
* Public functions
@ -664,8 +689,8 @@ void *ay8910_start_ym(sound_type chip_type, int sndindex, int clock, const ay891
{
ay8910_context *info;
info = (ay8910_context*) auto_malloc(sizeof(*info));
memset(info, 0, sizeof(*info));
info = malloc(sizeof(ay8910_context));
memset(info, 0, sizeof(ay8910_context));
info->index = sndindex;
info->intf = intf;
if ((info->intf->flags & AY8910_SINGLE_OUTPUT) != 0)
@ -710,7 +735,7 @@ void *ay8910_start_ym(sound_type chip_type, int sndindex, int clock, const ay891
info->channel = stream_create(0,info->streams,clock / 8 ,info,ay8910_update);
ay8910_set_clock_ym(info,clock);
ay8910_statesave(info, sndindex);
//ay8910_statesave(info, sndindex);
return info;
}
@ -754,7 +779,7 @@ void ay8910_set_volume(int chip,int channel,int volume)
void ay8910_set_clock_ym(void *chip, int clock)
{
ay8910_context *psg = chip;
stream_set_sample_rate(psg->channel, clock / 8 );
//stream_set_sample_rate(psg->channel, clock / 8 );
}
void ay8910_write_ym(void *chip, int addr, int data)
@ -769,7 +794,7 @@ void ay8910_write_ym(void *chip, int addr, int data)
if (r == AY_ESHAPE || psg->regs[r] != data)
{
/* update the output buffer before changing the register */
stream_update(psg->channel);
//stream_update(psg->channel);
}
ay8910_write_reg(psg,r,data);
@ -798,16 +823,16 @@ int ay8910_read_ym(void *chip)
*/
if (psg->intf->portAread)
psg->regs[AY_PORTA] = (*psg->intf->portAread)(Machine, 0);
else
logerror("PC %04x: warning - read 8910 #%d Port A\n",activecpu_get_pc(),psg->index);
//else
//logerror("PC %04x: warning - read 8910 #%d Port A\n",activecpu_get_pc(),psg->index);
break;
case AY_PORTB:
if ((psg->regs[AY_ENABLE] & 0x80) != 0)
logerror("warning: read from 8910 #%d Port B set as output\n",psg->index);
if (psg->intf->portBread)
psg->regs[AY_PORTB] = (*psg->intf->portBread)(Machine, 0);
else
logerror("PC %04x: warning - read 8910 #%d Port B\n",activecpu_get_pc(),psg->index);
//else
// logerror("PC %04x: warning - read 8910 #%d Port B\n",activecpu_get_pc(),psg->index);
break;
}
return psg->regs[r];
@ -819,7 +844,7 @@ int ay8910_read_ym(void *chip)
*
*************************************/
static void *ay8910_start(const char *tag, int sndindex, int clock, const void *config)
void *ay8910_start(const char *tag, int sndindex, int clock, const void *config)
{
static const ay8910_interface generic_ay8910 =
{
@ -831,7 +856,8 @@ static void *ay8910_start(const char *tag, int sndindex, int clock, const void *
return ay8910_start_ym(SOUND_AY8910, sndindex+16, clock, intf);
}
static void *ym2149_start(const char *tag, int sndindex, int clock, const void *config)
/*static void
*ym2149_start(const char *tag, int sndindex, int clock, const void *config)
{
static const ay8910_interface generic_ay8910 =
{
@ -841,7 +867,7 @@ static void *ym2149_start(const char *tag, int sndindex, int clock, const void *
};
const ay8910_interface *intf = (config ? config : &generic_ay8910);
return ay8910_start_ym(SOUND_YM2149, sndindex+16, clock, intf);
}
}*/
static void ay8910_stop(void *chip)
{
@ -902,19 +928,34 @@ void ay8912_get_info(void *token, UINT32 state, sndinfo *info)
{
switch (state)
{
case SNDINFO_PTR_START: info->start = ay8910_start; break;
case SNDINFO_STR_NAME: info->s = "AY-3-8912A"; break;
default: ay8910_get_info(token, state, info); break;
case SNDINFO_PTR_START:
info->start = ay8910_start;
break;
case SNDINFO_STR_NAME:
info->s = "AY-3-8912A";
break;
default:
ay8910_get_info(token, state, info);
break;
}
}
void ay8913_get_info(void *token, UINT32 state, sndinfo *info)
{
switch (state)
{
case SNDINFO_PTR_START: info->start = ay8910_start; break;
case SNDINFO_STR_NAME: info->s = "AY-3-8913A"; break;
default: ay8910_get_info(token, state, info); break;
switch (state) {
case SNDINFO_PTR_START:
info->start = ay8910_start;
break;
case SNDINFO_STR_NAME:
info->s = "AY-3-8913A";
break;
default:
ay8910_get_info(token, state, info);
break;
}
}
/*
@ -954,26 +995,29 @@ void ymz284_get_info(void *token, UINT32 state, sndinfo *info)
{
case SNDINFO_PTR_START: info->start = ym2149_start; break;
case SNDINFO_STR_NAME: info->s = "YMZ284"; break;
default: ay8910_get_info(token, state, info); break;
default:
ay8910_get_info(token, state, info);
break;
}
}
void ymz294_get_info(void *token, UINT32 state, sndinfo *info)
{
switch (state)
{
case SNDINFO_PTR_START: info->start = ym2149_start; break;
case SNDINFO_STR_NAME: info->s = "YMZ294"; break;
default: ay8910_get_info(token, state, info); break;
switch (state) {
case SNDINFO_PTR_START:
info->start = ym2149_start;
break;
case SNDINFO_STR_NAME:
info->s = "YMZ294";
break;
default:
ay8910_get_info(token, state, info);
break;
}
}
*/
int
main(int argc, char* argv[])
{
printf("ay8910test.\n");
return 0;
}
/*************************************
*
@ -1002,9 +1046,25 @@ WRITE8_HANDLER( ay8910_control_port_1_w ) { ay8910_write_ym(sndti_token(SOUND_AY
WRITE8_HANDLER( ay8910_control_port_2_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 2),0,data); }
WRITE8_HANDLER( ay8910_control_port_3_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 3),0,data); }
WRITE8_HANDLER( ay8910_control_port_4_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 4),0,data); }
WRITE16_HANDLER( ay8910_control_port_0_lsb_w ) { if (ACCESSING_BITS_0_7) ay8910_write_ym(sndti_token(SOUND_AY8910, 0),0,data & 0xff); }
WRITE16_HANDLER( ay8910_control_port_1_lsb_w ) { if (ACCESSING_BITS_0_7) ay8910_write_ym(sndti_token(SOUND_AY8910, 1),0,data & 0xff); }
WRITE16_HANDLER( ay8910_control_port_2_lsb_w ) { if (ACCESSING_BITS_0_7) ay8910_write_ym(sndti_token(SOUND_AY8910, 2),0,data & 0xff); }
WRITE16_HANDLER( ay8910_control_port_0_lsb_w )
{
if (ACCESSING_BITS_0_7)
ay8910_write_ym(sndti_token(SOUND_AY8910, 0),0,data & 0xff);
}
WRITE16_HANDLER( ay8910_control_port_1_lsb_w )
{
if (ACCESSING_BITS_0_7)
ay8910_write_ym(sndti_token(SOUND_AY8910, 1),0,data & 0xff);
}
WRITE16_HANDLER( ay8910_control_port_2_lsb_w )
{
if (ACCESSING_BITS_0_7)
ay8910_write_ym(sndti_token(SOUND_AY8910, 2),0,data & 0xff);
}
WRITE16_HANDLER( ay8910_control_port_3_lsb_w ) { if (ACCESSING_BITS_0_7) ay8910_write_ym(sndti_token(SOUND_AY8910, 3),0,data & 0xff); }
WRITE16_HANDLER( ay8910_control_port_4_lsb_w ) { if (ACCESSING_BITS_0_7) ay8910_write_ym(sndti_token(SOUND_AY8910, 4),0,data & 0xff); }
WRITE16_HANDLER( ay8910_control_port_0_msb_w ) { if (ACCESSING_BITS_8_15) ay8910_write_ym(sndti_token(SOUND_AY8910, 0),0,data >> 8); }
@ -1028,3 +1088,29 @@ WRITE16_HANDLER( ay8910_write_port_1_msb_w ) { if (ACCESSING_BITS_8_15) ay8910_w
WRITE16_HANDLER( ay8910_write_port_2_msb_w ) { if (ACCESSING_BITS_8_15) ay8910_write_ym(sndti_token(SOUND_AY8910, 2),1,data >> 8); }
WRITE16_HANDLER( ay8910_write_port_3_msb_w ) { if (ACCESSING_BITS_8_15) ay8910_write_ym(sndti_token(SOUND_AY8910, 3),1,data >> 8); }
WRITE16_HANDLER( ay8910_write_port_4_msb_w ) { if (ACCESSING_BITS_8_15) ay8910_write_ym(sndti_token(SOUND_AY8910, 4),1,data >> 8); }
int
main(int argc, char* argv[])
{
//running_machine *machine;
INT16 sounddata[100];
int i=0, sndindex=1, clock=500000;
ay8910_context *info;
const ay8910_interface ay8910_inf;
int sample_rate = 11025;
printf("ay8910test.\n");
for (i=0; i<100; ++i)
sounddata[i] = 32000 + 100 * i;
//machine = malloc(sizeof(running_machine));
sdlaudio_init(sample_rate);
info = ay8910_start(NULL, sndindex, clock, &ay8910_inf);
while (1)
osd_update_audio_stream(sample_rate,sounddata,100);
sdl_kill();
//free(machine);
return 0;
}

View File

@ -2,8 +2,8 @@
#define __AY8910_H__
//#include "osdcomm.h"
#include "mamecore.h"
#include "memory.h"
//#include "mamecore.h"
//#include "memory.h"
//typedef UINT32 offs_t;
//typedef UINT8 (*read8_machine_func) (ATTR_UNUSED running_machine *machine, ATTR_UNUSED offs_t offset);
@ -142,6 +142,7 @@ WRITE16_HANDLER( ay8910_write_port_4_msb_w );
/*********** An interface for SSG of YM2203 ***********/
void *ay8910_start_ym(sound_type chip_type, int sndindex, int clock, const ay8910_interface *intf);
void *ay8910_s(void *chip);
void ay8910_stop_ym(void *chip);
void ay8910_reset_ym(void *chip);

View File

@ -10,7 +10,7 @@
***************************************************************************/
#pragma once
#pragma once
#ifndef __DEPRECAT_H__
#define __DEPRECAT_H__

View File

@ -56,6 +56,17 @@ typedef UINT64 FPTR;
typedef UINT32 FPTR;
#endif
struct _running_machine
{
/* audio-related information */
int sample_rate; /* the digital audio sample rate */
/* debugger-related information */
UINT32 debug_flags; /* the current debug flags */
void * driver_data; /* drivers can hang data off of here instead of using globals */
};
/* These are forward struct declarations that are used to break
circular dependencies in the code */

View File

@ -14,12 +14,12 @@
#ifndef __MEMORY_H__
#define __MEMORY_H__
/*
#include "mamecore.h"
#include "devintrf.h"
#include "tokenize.h"
#include "osdcomm.h"
*/
/***************************************************************************
CONSTANTS
***************************************************************************/

View File

@ -150,7 +150,8 @@ typedef enum _sound_type sound_type;
/* Sound information constants */
enum
{
/* --- the following bits of info are returned as 64-bit signed integers --- */
/* --- the following bits of info are returned as 64-bit signed
* integers --- */
SNDINFO_INT_FIRST = 0x00000,
SNDINFO_INT_ALIAS = SNDINFO_INT_FIRST, /* R/O: alias to sound type for (type,index) identification */

View File

@ -12,15 +12,16 @@
#ifndef STREAMS_H
#define STREAMS_H
#include "attotime.h"
#include "osdcomm.h"
#include "deprecat.h"
#include "mamecore.h"
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
typedef struct _sound_stream sound_stream;
#if 0
typedef void (*stream_update_func)(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
@ -36,6 +37,7 @@ typedef void (*stream_update_func)(void *param, stream_sample_t **inputs, stream
/* initialize the streams engine */
void streams_init(running_machine *machine, attoseconds_t update_subseconds);
#endif
/* set the tag to be associated with all streams allocated from now on */
void streams_set_tag(running_machine *machine, void *streamtag);

191
reference/disk.txt Normal file
View File

@ -0,0 +1,191 @@
Diskettstasjonkontrolleren i TIKI-100 Rev C
-------------------------------------------
TIKI-100 inneholder en FD1767PL-02 eller en FD1797-PL diskettstasjonkontroller
fra Western Digital. I TIKI-100 er ikke FD17xx kretsens INTRQ tilkoblet, så
den vil ikke kunne generere interrupts.
FD17xx kretsen kontrolleres gjennom 4 I/O porter:
I/O-port 10H: Statusord / styreord
Ved skriving er dette kommandoregisteret. Ved lesing er det statusregisteret.
I/O-port 11H: Spornummer
Her kan spor-registeret skrives og leses.
I/O-port 12H: Sektornummer
Her kan sektor-registeret skrives og leses.
I/O-port 13H: Dataregister
Gjennom denne porten leses og skrives data til diskett.
Oversikt over kommandoer
Type Navn Bits i kommandoregister
---------------------------------------------
I Restore 0 0 0 0 h V r1 r0
I Seek 0 0 0 1 h V r1 r0
I Step 0 0 1 T h V r1 r0
I Step-In 0 1 0 T h V r1 r0
I Step-Out 0 1 1 T h V r1 r0
II Read Sector 1 0 0 m 1 1 U 0
II Write Sector 1 0 1 m 1 1 U a0
III Read Address 1 1 0 0 0 1 U 0
III Read Track 1 1 1 0 0 1 U 0
III Write Track 1 1 1 1 0 1 U 0
IV Force Interrupt 1 1 0 1 0 0 0 0
r1,r0: Stepping Motor Rate
0 0 = 6 ms
0 1 = 12 ms
1 0 = 20 ms
1 1 = 30 ms
V: Track Number Verify Flag
0 = ikke verifiser
1 = sjekk at sporregisteret tilsvarer spornummeret i første ID-felt på
målsporet
h: Head Load
0 = ikke senk lese/skrive hodet
1 = senk lese/skrive hodet
T: Track Update Flag
0 = ikke oppdater sporregister
1 = oppdater sporregister etter endt operasjon
U: Side select
0 = velg side 0
1 = velg side 1
m: Multiple Record Flag
0 = les/skriv kun 1 sektor
1 = les/skriv sektorer helt til hele sporet er dekket
a0: Data Address Mark
0 = dataadressemerket er 0fbH
1 = dataadressemerket er 0f8H (slettet dataadressemerke)
Statusregister
Type I kommandoer:
Bit Navn Forklaring
----------------------------------------------------------------------------
7 Not ready Stasjonen er ikke klar
6 Protected Skrivebeskyttet diskett
5 Alltid 1 i TIKI-100
4 Seek error Ønsket spor ikke verifisert
3 CRC error Gal CRC i ID-felt
2 Track 0 Hodet står over spor 0
1 Index Angir begynnelsen av første sektor
0 Busy Kommando under utførelse
Type II og III kommandoer:
Bit Navn Forklaring
----------------------------------------------------------------------------
7 Not ready Samme som for type I
6 Protected Lesekommandoer: ikke brukt
Skrivekommandoer: diskett er skrivebeskyttet
5 Record type/Write fault Les sektor: 1 = slettet dataadressemerke
0 = vanlig dataadressemerke
Skrivekommandoer: Skrivefeil
4 Record not found Ønsket spor, sektor eller side ikke funnet
3 CRC error Sammen med bit 4: Feil sjekksum i kontrollfelt
Uten bit 4: Feil sjekksum i datafelt
2 Lost data Prosessor har ikke håndtert DRQ raskt nok
1 Data request Kopi av DRQ, klar for overføring av neste byte
0 Busy Kommando under utførelse
Busy flagget settes når en kommando er under utførelse. Ingen kommando, utenom
"Force Interrupt" må legges inn i kommandoregisteret mens Busy er satt.
Type I kommandoer
Restore
Før hodet til spor 0 og oppdater sporregisteret.
Hvis ikke sporet finnes innen 255 flytt, settes "Seek error" i
statusregisteret.
Seek
Denne kommandoen antar at sporregisteret inneholder gjeldende spornummer og
dataregisteret inneholder ønsket målspor.
Fører hodet til sporet angitt i dataregisteret og oppdaterer sporregisteret.
Step
Flytt hodet ett spor i samme retning som det ble flyttet sist.
Step-In
Flytt hodet ett spor innover (mot økende spornummer).
Step-Out
Flytt hodet ett spor utover (mot spor 0).
Type II kommandoer
Legg ønsket sektor i sektorregisteret.
Read Sector
Overfører ønsket sektor byte for byte gjennom dataregisteret. Hver gang en byte
er klar for overføring settes "Data request" flagget i statusregisteret. Etter
endt operasjon settes "Recort type" flagget i statusregisteret.
Write Sector
Skriver ønsket sektor til diskett. Hver gang en byte kan skrives, settes "Data
request" flagget i statusregisteret. Diskettkontrolleren lager selv ID feltet
med riktig dataadressemerke og CRC.
Type III kommandoer
Read Address
Overfører gjennom dataregisteret det neste ID feltet som passeres. Hver gang en
byte er klar for overføring settes "Data request" flagget i statusregisteret.
ID feltet består av seks bytes:
1 spor
2 side
3 sektor
4 sektorlengde
0 = 128 bytes
1 = 256 bytes
2 = 512 bytes
3 = 1024 bytes
5,6 CRC
Read Track
Overfører hele sporet gjennom dataregisteret, inkludert ID felt og mellomrom.
Hver gang en byte er klar for overføring settes "Data request" flagget i
statusregisteret.
Write Track
Skriver et spor til diskett, inkludert mellomrom og ID felter. Brukes til
formatering av diskett. Bytes overføres gjennom dataregisteret. "Data request"
settes i statusregisteret når det er klart for neste byte.
Bytes f5H-feH tolkes som dataadressemerke. Spesielt tolkes f5H-f7H slik:
f5H Skriv a1H, nullstill CRC generator.
f6H Skriv c2H
f7H Skriv 2 bytes CRC.
Type IV kommandoer
Force Interrupt
Brukes til å stanse en pågående operasjon før den avsluttes på normalt vis,
eller sikre type I statusregister.
Hvis denne kommandoen settes mens en annen kommando utføres (busy = 1), vil
busy settes lik 0 og resten av statusregisteret er uforandret.
Hvis busy = 0 når denne kommandoen utføres vil statusregisteret slettes /
oppdateres og reflektere type I statusregister.
---
21 januar 2001
Asbjørn Djupdal, djupdal@stud.ntnu.no

47
reference/ioporter.txt Normal file
View File

@ -0,0 +1,47 @@
I/O-porter i TIKI-100 Rev C
---------------------------
Adresse Retning Funksjon
--------------------------------------------------------
00-03 les/skriv Tastatur
04 les/skriv Seriekanal A, dataord
05 les/skriv Seriekanal B, dataord
06 les/skriv Seriekanal A, statusord/styreord
07 les/skriv Seriekanal B, statusord/styreord
08 les/skriv Parallellport A, dataord
09 les/skriv Parallellport B, dataord
0A les/skriv Parallellport A, statusord/styreord
0B les/skriv Parallellport B, statusord/styreord
0C-0F skriv Grafikk modus
10 les/skriv Diskettstasjon statusord/styreord
11 les/skriv Diskettstasjon spornummer-register
12 les/skriv Diskettstasjon sektor-register
13 les/skriv Diskettstasjon dataregister
14-15 skriv Grafikk fargeregister (pallett)
16 skriv Lyd og scroll peker
17 les/skriv Lyd og scroll data
18 les/skriv Tellerkrets (CTC) kanal 0
19 les/skriv Tellerkrets (CTC) kanal 1
1A les/skriv Tellerkrets (CTC) kanal 2
1B les/skriv Tellerkrets (CTC) kanal 3
1C-1F skriv Systemregister
Ledige I/O-porter:
20-7F Reservert TIKI-DATA
20-27 Winchester controller
60-6F Analog I/O (SINTEF)
60-67 RVO-kort (DIGI I/O)
70-77 Analog/Digital I/O
78-7B Lyspenn interface
7E-7F 8088/87 16 bit prosessor med 128k RAM
80-FF Ledig for bruk av andre enn TIKI-DATA
Alle adresser er i hex.
Der flere portadresser er angitt for ett og samme register, bør du benytte deg
av den første.
---
18 juni 2000
Asbjørn Djupdal, djupdal@stud.ntnu.no

46
reference/lyd.txt Normal file
View File

@ -0,0 +1,46 @@
Lyd og scrolling i TIKI-100 Rev C
---------------------------------
TIKI-100 inneholder en AY-3-8912 chip. Dette er en standard lydkrets som finnes
i mange andre datamaskiner, bl.a Amstrad CPC og ZX-Spectrum. Siden det finnes
mange gode tekster som omhandler programmering av denne kretsen, tar jeg bare
med det som gjelder spesielt for TIKI her.
AY-3-8912 har 15 registre som kontrollerer kretsens virkemåte. Den har 2
funksjoner; Hovedfunksjonen er lydgenerering, men den inneholder også en 8 bits
dataport. Denne dataporten er i TIKI-100 brukt til vertikal scrolling av
skjermen.
Tilgang til AY-3-8912 skjer gjennom 2 I/O-porter:
I/O-port 16H: Lyd og scroll peker
For å få tilgang til et av registrene i AY-3-8912, må det aktuelle
registernummeret skrives til denne porten.
I/O-port 17H: Lyd og scroll data
Etter at registernummeret er skrevet til I/O-port 16H, kan data til det aktuelle
registeret skrives/leses i denne porten.
Hardware scrolling
Som nevnt tidligere, benyttes AY-3-8912's dataport (register 14) til vertikal
scrolling. Hver gang prosessor eller videokrets prøver å få tilgang til grafikk-
hukommelsen, adderes innholdet i denne dataporten multiplisert med 128 til
verdien på adressebussen. Hvis f.eks prosessoren skal ha tak i innholdet i
adresse 0 i grafikkram, og innholdet i AY-3-8912's dataport er 10, vil
prosessoren i stedet få innholdet i adresse 0 + (10*128) MOD 32768 = 1280. Selv
om data i grafikkram ikke fysisk skifter plass, vil det i praksis føles som om
grafikkram-innholdet hopper oppover like mange linjer som dataportens innhold
øker med i verdi.
Med andre ord: For å scrolle skjermen oppover x antall linjer, legg x til
verdien som allerede ligger i AY-3-8912's dataport.
For å scrolle skjermen nedover x antall linjer, trekk x fra verdien som
allerede ligger i AY-3-8912's dataport.
---
26 juni 2001
Asbjørn Djupdal, djupdal@stud.ntnu.no

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

116
reference/parallell.txt Normal file
View File

@ -0,0 +1,116 @@
Parallellporter i TIKI-100 Rev C
--------------------------------
TIKI-100 inneholder en Z80 PIO krets med 2 stk. 8-bits I/O porter
(hver med kvitteringssignalene RDY og STB).
Begge disse er koblet opp til parallellport P3. Se portbeskrivelsen
for mer informasjon om pinnetilordning.
Z80 PIO kontrolleres gjennom 4 I/O porter:
I/O-port 08H: Parallellport A, dataord
Her leses og skrives data for parallellport A.
I/O-port 09H: Parallellport B, dataord
Her leses og skrives data for parallellport B.
I/O-port 0AH: Parallellport A, styreord
Her skrives kontrollregisteret til parallellport A.
I/O-port 0BH: Parallellport B, styreord
Her skrives kontrollregisteret til parallellport B.
Operasjonsmodi
Parallellportene kan settes til en av 4 modi:
Modus 0: Data ut. Data skrevet til dataregisteret blir satt rett ut på
porten. De kan også leses tilbake. Når gyldige data settes ut
på porten, går RDY høy. STB kan settes høy av eksternt utstyr
for å indikere at data er lest.
Modus 1: Data inn. Porten klokker inn data utenfra når det eksterne
utstyret setter STB høy. Data kan hentes inn til CPU ved å
lese dataregisteret. Da blir samtidig RDY høy, og indikerer
til det eksterne utstyret at porten er klar for en ny byte.
Når STB settes høy, går RDY lav, og kretsen kan gi interrupt.
Modus 2: Bidireksjonal (både inn og ut). Bare port A kan fungere i
modus 2. Når port A settes til modus 2, må samtidig port B
settes til modus 2 og port B må settes til å ikke generere
interrupts.
Data ut er lik modus 0, bortsett fra at data bare settes ut
når ASTB er lav.
Data inn er lik modus 1, bortsett fra at kvitteringssignalene
og interruptmulighetene til port B benyttes.
Modus 3: Bit kontroll. Individuelle bits i parallellporten kan settes
enten til inn eller ut. RDY og STB er ikke brukt. I stedet
genereres en interrupt hvis interruptbetingelsene til
input-pinnene bestemt under programmering av porten er
oppfyllt.
Programmering
Programmering av porten foregår ved skriving til portens
kontrollregister.
Følgende styreord kan skrives til kontrollregisteret:
Mode Control Word:
Bit 6-7: Velger modus:
Bit 7 Bit 6
0 0 Modus 0
0 1 Modus 1
1 0 Modus 2
1 1 Modus 3
Når modus 3 velges, MÅ etterfølgende ord skrevet til
kontrollregisteret være et retningsord, der en ener i en
bitposisjon medfører at tilsvarende I/O-pinne vil bli en
inngang, mens en nuller vil medføre at I/O-pinnen blir en
utgang.
Bit 4-5: Ubrukt
Bit 0-3: Må settes til 1111 (identifiserer at dette er Mode Control
Word).
Interrupt Control Word:
Bit 7 = 1: Skrur på interruptfunksjonen
Bit 7 = 0: Skrur av interruptfunksjonen
Bit 6 = 1: OG funksjon, alle bit med i interruptbetingelsen må gå til
den definerte tilstanden for at interrupt skal genereres.
Bit 6 = 0: ELLER funksjon, interrupt genereres når minst ett bit går
til den definerte tilstanden.
Bit 5 = 1: Definert tilstand er høy
Bit 5 = 0: Definert tilstand er lav
Bit 4 = 1: Kun utvalgte bit er med i interruptbetingelsen. Neste byte
skrevet til kontrollregisteret må være et maskeord. Dersom
et utvalgt bit i maskeordet er satt vil den tilsvarende
pinnen i parallellporten IKKE monitoreres for interrupt.
Dersom bit 4 er satt, MÅ det altså skrives et slikt
maskeord til kontrollregisteret umiddelbart etterpå.
Uansett modus, ved å sette bit 4 til 1 vil alle ventende
interrupts bli slettet.
Bit 0-3: Må settes til 0111 (identifiserer at dette er Interrupt
Control Word).
Interrupt Disable Word:
Bit 7 = 1: Skrur på interrupts
Bit 7 = 0: Skrur av interrupts
Bit 4-6: Ubrukt
Bit 0-3: Må settes til 0011 (identifiserer at dette er Interrupt
Disable Word).
Interrupt Vector Word:
Bit 1-7: Setter interrupt vektoren som skal benyttes ved interrupts
(med implisitt 0 i minst signifikante bit).
Bit 0: Må settes til 0 (identifiserer at dette er Interrupt Vector
word).
---
18 august 2002
Asbjørn Djupdal, djupdal@stud.ntnu.no

180
reference/serie.txt Normal file
View File

@ -0,0 +1,180 @@
Serieporter i TIKI-100 Rev C
----------------------------
TIKI-100 benytter seg av en Z80 DART som inneholder to asynkrone RS-232
serieporter.
DART kontrolleres gjennom 4 I/O porter:
I/O port 04H: Seriekanal A, dataord
Gjennom denne porten leses og skrives data til serieport A.
I/O port 05H: Seriekanal B, dataord
Gjennom denne porten leses og skrives data til serieport B.
I/O port 06H: Seriekanal A, statusord/styreord
Ved skriving er dette kommandoregisteret til port A, ved lesing er det
statusregisteret.
I/O port 07H: Seriekanal B, statusord/styreord
Ved skriving er dette kommandoregisteret til port B, ved lesing er det
statusregisteret.
DART's interne registre
Hver seriekanal har 3 leseregistre og 6 skriveregistre. Disse kan nås gjennom to
etterfølgende lese/skrive-operasjoner til kanalens kommandoregister. Først
skrives en peker til kommandoregisteret som angir hvilket register som ønskes,
deretter skrives/leses det aktuelle registeret gjennom den samme I/O
porten. Dersom en lese/skrive operasjon ikke kommer etter en gyldig peker, vil
register 0 benyttes.
Leseregister 0
Bit 7 = 1: BRK. Seriekanalen ligger på +V i mer enn 2 tegnlengder.
Bit 6: Ikke i bruk.
Bit 5 = 1: CTS. Modemsignalet CTS er satt.
Bit 3-4: Ikke i bruk.
Bit 2 = 1: TBE. Transmit Buffer Empty. Sender har sendt tegn og er klar for et
nytt. Rett etter initialisering av seriekanal kan et tegn
skrives til dataporten uten å sjekke denne biten først. Dette
fordi denne biten settes først etter at et tegn har blitt sendt,
og vil derfor ikke være satt før første tegn er sendt.
Bit 1 = 1: INT. Interrupt er satt
Bit 0 = 1: RXA. Receive Character Available, dvs. nytt tegn mottatt og kan leses
ut av dataporten. Denne biten blir nullstilt etter at dataporten
har blitt lest.
Leseregister 1
Bit 7: Ikke i bruk.
Bit 6 = 1: FF. Format feil, f.eks feil antall stopbits.
Bit 5 = 1: RXO. Receiver Overflow, dvs innkommende tegn har kommet fortere enn
de har blitt lest ut av dataporten.
Bit 4 = 1: PF. Paritetsfeil.
Bit 1-3: Ikke i bruk.
Bit 0 = 1: AS. Alt sendt.
Leseregister 2
Interruptvektor kan leses ut av dette registeret. Bit 0-3 kan variere, avhengig
av status dersom "Status affects vector" er satt.
Skriveregister 0
I skriveregister 0 settes peker for det neste registeret man vil nå gjennom
denne porten.
Bit 6-7: Ikke i bruk
Bit 3-5: Peker til neste register som skal nås
Bit 5 Bit 4 Bit 3 Register
0 0 0 0
0 0 1 1
0 1 0 2
0 1 1 3
1 0 0 4
1 0 1 5
Bit 0-2: Nullstillingskommando
Bit 2 Bit 1 Bit 0 Funksjon
0 1 0 Nullstill status interrupt
0 1 1 Nullstill hele kanalen
1 0 0 Sett interrupt når neste serietegn
mottas
1 0 1 Nullstill senderinterrupt
1 1 0 Nullstill feilmelding
1 1 1 Retur fra interrupt (bare kanal A)
Skriveregister 1
Bit 5-7: Ikke i bruk.
Bit 3-4: RXI.
Bit 4 Bit 3 Type mottakerinterrupt
0 0 Ingen mottaker interrupt
0 1 Sett mottaker interrupt ved første mottatte tegn
1 0 Interrupt på alle mottatte tegn, paritet endrer
vektor (aner ikke hva det vil si)
1 1 Interrupt på alle mottatte tegn, paritet endrer
ikke vektor
Bit 2 = 1: SAV. Status Affects Vector, dvs interruptvektoren endres avhengig av
årsaken til interruptet.
Bit 1 = 1: TXI. Sett interrupt når senderen er klar for neste tegn.
Bit 0 = 1: EXI. Sett interrupt ved endring av eksterne signaler.
Skriveregister 2
Interruptvektor, skriv inn ønsket interruptvektor her. Interruptvektoren er delt
mellom begge seriekanalene.
Skriveregister 3
Bit 6-7: Antall bits pr. tegn i mottakeren
Bit 6 Bit 5 Antall bits
0 0 5
0 1 6
1 0 7
1 1 8
Bit 5 = 1: AE. Auto Enable, dvs senderen slås automatisk av og på med signalet
CTS.
Bit 1-4: Ikke i bruk.
Bit 0 = 1: RXE. Receiver Enable, dvs starter mottakerfunksjon.
Skriveregister 4
Bit 6-7: Neddeling av klokkefrekvensen, dvs hvilket tall innkommende
klokkefrekvens skal deles med for å få antall baud.
Bit 7 Bit 6 Neddeling
0 0 1
0 1 16
1 0 32
1 1 64
Bit 4-5: Ikke i bruk.
Bit 2-3: Antall stopbits
Bit 3 Bit 2 Antall
0 0 Ugyldig
0 1 1
1 0 1,5
1 1 2
Bit 1 = 1: PN. Like paritet.
Bit 0 = 1: P. Paritet skal benyttes.
Skriveregister 5
Bit 7: Ikke i bruk.
Bit 5-6: TN Antall bits pr. tegn i senderen
Bit 6 Bit 5 Antall
0 0 5
0 1 7
1 0 6
1 1 8
Bit 4 = 1: SB. Send Break, dvs legg serieutgangen på -V.
Bit 3 = 1: TXE. Start senderfunksjonen.
Bit 2: Ikke i bruk.
Bit 1 = 1: RTS. Slå på Request To Send.
Bit 0: Ikke i bruk.
Interrupts
Jeg er usikker på en del av DART's interruptgenerering. Dette er hva jeg tror:
Interruptvektor deles mellom kanalene.
Dersom "Status Affects Vector" er satt, vil interruptvektoren som benyttes
forandres avhengig av status. Vektoren forandres slik:
Sender B, normal: Bit 3 = 0, bit 2 = 0, bit 1 = 0
Sender B, feil: Bit 3 = 0, bit 2 = 0, bit 1 = 1
Mottaker B, normal: Bit 3 = 0, bit 2 = 1, bit 1 = 0
Mottaker B, feil: Bit 3 = 0, bit 2 = 1, bit 1 = 1
Sender A, normal: Bit 3 = 1, bit 2 = 0, bit 1 = 0
Sender A, feil: Bit 3 = 1, bit 2 = 0, bit 1 = 1
Mottaker A, normal: Bit 3 = 1, bit 2 = 1, bit 1 = 0
Mottaker A, feil: Bit 3 = 1, bit 2 = 1, bit 1 = 1
---
28 juni 2001
Asbjørn Djupdal, djupdal@stud.ntnu.no

38
reference/sysreg.txt Normal file
View File

@ -0,0 +1,38 @@
Systemregisteret i TIKI-100 Rev C
---------------------------------
I/O-port 1CH - Systemregister
Dette registeret benyttes til valg av minnekonfigurasjon, styring av lamper på
tastaturet, og styring av div diskett-funksjoner.
Bit nr Navn Aktiv Funksjon
----------------------------------------------------------
7 LMP1 LAV Lys i LOCK-tast lampe
6 MOTON HØY Slår på diskett-motor
5 LMP0 LAV Lys i GRAFIKK-tast lampe
4 SDEN HØY Enkel skrivetetthet på diskett
3 VIRE HØY Grafikk RAM i området 0000-7FFF
2 ROME LAV EPROM i området 0000-3FFF
1 DRIS1 HØY Velger diskettstasjon 1
0 DRIS0 HØY Velger diskettstasjon 0
Minnekonfigurasjon:
Bit 3 Bit 2 | Adresseområde
VIRE ROME | 0000-3FFF 4000-7FFF 8000-FFFF
---------------------------+------------------------------------
0 0 | EPROM RAM RAM
0 1 | RAM RAM RAM
1 0 | Reservert (ikke i bruk)
1 1 | GFX-RAM GFX-RAM RAM
Som du sikkert ser, har EPROM'en et adresseområde på 16k. Disse er fordelt på 2
sokler (U10 og U9) med hver sin 8k EPROM. Kun den første (U10) er i bruk, men
man kan sette inn en standard 2k, 4k eller 8k 28 pins EPROM i den andre sokkelen
(U9) hvis ønskelig. Den vil i såfall få området 2000-3FFF.
---
21 juni 2000
Asbjørn Djupdal, djupdal@stud.ntnu.no

39
reference/tastatur.txt Normal file
View File

@ -0,0 +1,39 @@
Tastaturet i TIKI-100 Rev. C
----------------------------
Tastaturet består av en tastaturmatrise på 8 rader og 12 kolonner.
I/O-port 00H: Tastatur
Denne porten benyttes ved avlesning av tastaturet. All skriving til denne porten
nullstiller / resetter avlesningen og må gjøres før avlesning begynner. Deretter
kan hver enkelt tastatur kolonne avleses ved gjentatt lesing av denne porten.
Etter 12 leseoperasjoner har man hentet inn alle tastaturkolonnene.
Satt bit betyr tast IKKE nedtrykket.
F.eks: Hvis du etter å ha resatt tastaturet med en skriveoperasjon til port 0,
leser verdien 01111111B, betyr det at CTRL er nedtrykket.
Tastaturmatrise:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
----+---------+---------+---------+---------+---------+---------+---------+---------+
1 | CTRL | SHIFT | BRYT | RETUR | MLMROM | / (num) | SLETT | |
2 | GRAFIKK | 1 | ANGRE | a | < | z | q | LOCK |
3 | 2 | w | s | x | 3 | e | d | c |
4 | 4 | r | f | v | 5 | t | g | b |
5 | 6 | y | h | n | 7 | u | j | m |
6 | 8 | i | k | , | 9 | o | l | . |
7 | 0 | p | ø | - | + | å | æ | HJELP |
8 | @ | ^ | ' | VENSTRE | UTVID | F1 | F4 | SIDEOPP |
9 | F2 | F3 | F5 | F6 | OPP | SIDENED | VTAB | NED |
10 | + (num) | - (num) | * (num) | 7 (num) | 8 (num) | 9 (num) | % (num) | = (num) |
11 | 4 (num) | 5 (num) | 6 (num) | HTAB | 1 (num) | 0 (num) | . (num) | |
12 | HJEM | HØYRE | 2 (num) | 3 (num) | ENTER | | | |
----+---------+---------+---------+---------+---------+---------+---------+---------+
(num) betyr at tasten er på det numeriske tastaturet.
---
27 august 2000
Asbjørn Djupdal, djupdal@stud.ntnu.no

54
reference/teller.txt Normal file
View File

@ -0,0 +1,54 @@
Tellere i TIKI-100 Rev C
------------------------
TIKI-100 inneholder en Z80 CTC krets med 4 stk. 8-bits tellere.
Hver teller har en inngang og en utgang.
Slik er tellerkanalene koblet i TIKI-100:
Kanal 0 inn: 2MHz
Kanal 1 inn: 2MHz
Kanal 2 inn: Kanal 0 ut
Kanal 3 inn: Kanal 2 ut
Kanal 0 ut: BAR 0, til seriekanal A
Kanal 1 ut: BAR 1, til seriekanal B
Kanal 2 ut: BAR 2, til seriekanal A dersom jumper ST 28 B er kortsluttet
Normalt benyttes kanal 0 og 1 til å generere klokkefrekvenser til seriekanalene,
mens kanal 3 genererer avbruddssignaler.
Alternativt kan kanal 2 brukes til å generere klokkefrekvenser til seriekanal A
dersom ekstra lave hastigheter er nødvendig. Da kreves det at en bøyle (jumper)
på kretskortet kortsluttes (jumper ST 28 B)
Tellerne teller alltid ned fra en startverdi (tidskonstanten).
Når telleren kommer til 0, settes en puls ut på utgangen, og genererer evt. et
avbrudd.
I/O-porter 18H, 19H, 1AH, 1BH: Tellerkrets kanal 0, 1, 2, 3
Alle disse portene brukes likt, og styrer hhv teller 0, 1, 2 og 3.
Skriving til port:
Bit 7 = 1: Interrupt når teller kommer til 0
Bit 6 = 1: Tellermodus, pulser på separat inngang telles
Bit 6 = 0: Timermodus, nedtelling av 4MHz klokke
Bit 5 = 1: Nedskalering 256 når bit 6=0
Bit 5 = 0: Nedskalering 16 når bit 6=0
Bit 4 = 1: Teller på positiv flanke (negativ flanke hvis bit 4 = 0)
Bit 3: Skal alltid være 0 i TIKI-100
Bit 2 = 1: Neste ord som skrives hit er tidskonstanten
Bit 1 = 1: Reset. Teller stoppes, men ingen registre endres. Hvis både bit 1 og
2 er 1, fortsetter telleren etter at tidskonstanten er skrevet.
Bit 0: ? (bør settes til 1?)
Lesing av port:
Avlest verdi gir antall pulser igjen til 0.
---
18 juni 2000
Asbjørn Djupdal, djupdal@stud.ntnu.no

66
reference/video.txt Normal file
View File

@ -0,0 +1,66 @@
Videokretsen i TIKI-100 Rev C
-----------------------------
TIKI-100 inneholder kun bitmap-grafikk, dvs ingen tekstbaserte moduser.
Prosessoren kan skrive direkte til skjermhukommelsen hvis bit 2 og 3 i
systemregisteret (1CH) er satt.
Grafikkhukommelsen representeres på skjermen på den intuitivt riktige måten.
128 bytes per linje, alle disse bytene er etter hverandre i RAM. Totalt 256
linjer:
+---------------------------------------+
|byte 0 ... byte 127 |
|byte 128 ... byte 255 |
| . |
| . |
| . |
| |
| |
| |
| |
| |
|byte 32640 ... byte 32767 |
+---------------------------------------+
I/O-port 0CH - Modusregister
Bit 7 = 1: Skriv farge. Ved hver HBLANK legges fargen i fargeregister 14H inn i
pallettplass angitt av bit 0-3
Bit 6: Ikke brukt
Bit 4-5: Velger oppløsning
Bit 5 Bit 4
0 0
0 1 2 farger, 1024 kolonner
1 0 4 farger, 512 kolonner
1 1 16 farger, 256 kolonner
Alle 16 fargene i palletten benyttes av videokretsen i alle moduser.
Dersom ikke paletten settes slik det er tenkt kommer det fargerikt
rot på skjermen i 2 og 4 fargers modus. For 2-fargers modus: Sett
farge 2,4,6,8,10,12,14 lik farge 0, og farge 1,3,5,7,9,11,13,15 lik
farge 1. For 4-fargers modus: Sett farge 4,8,12 lik farge 0, farge
5,9,13 lik farge 1, farge 6,10,14 lik farge 2, og farge 7,11,15 lik
farge 3.
Bit 0-3: Hvilken plass i palletten fargen i fargeregisteret skal legges inn i
(hvis bit 7 = 1)
I/O-port 14H - Fargeregister
Dette brukes til mellomlagring av en farge før den lagres i palletten (se
modusregister). Farger blandes slik:
Bit 5-7: Rød intensitet
Bit 2-4: Grønn intensitet
Bit 0-1: Blå intensitet
Registeret er invertert, dvs at 0 gir sterkest intensitet og 7 (3 for blåfarge)
gir svakest intensitet.
Hardware-scrolling
Hardware scrolling styres gjennom dataporten på lydkretsen AY-3-8912. Les mer om
dette i egen tekst.
---
27 juni 2001
Asbjørn Djupdal, djupdal@stud.ntnu.no