Thursday, 23 February 2012

Panasonic JR200 insides

Here are photographs from the board inside the Panasonic JR200UP. At the centre, little to the left, the MN1800 processor can be seen, a clone of Motorola 6802. Another very important chip is the MN1544, a 4-bit co-processor with its own memory, located in the bottom right section. Click on the images to see the high resolution versions, or open them in a new tab to download the full-size originals. I have photographed these images myself and they can be used freely.

Panasonic JR200 board from above.

The board from below.

Monday, 13 February 2012

Graphics on the Panasonic JR200U

This image was converted from a jpg of a photograph, posterized into 8 colours in the paint program Gimp, converted into a character set and laid out according to the video/attribute memory of Panasonic with a separate program written in Processing. The output binaries were transferred into CJR files using bin2cjr programmed by Markku Reunanen. The CJR files were then converted into WAV files, and loaded into a real Panasonic JR200 with Audacity. The image is taken with a camera and brought back to the mac for some editing before posting it on the blog. So, the image has made quite a journey!

What you see here is a redefined character set on a character display with attributes, not a bitmap. 256 characters of the ordinary character set plus the user-defined 64 characters gives a total of 320 characters. (The shown image uses 275 unique characters) The attributes in the video memory determine whether a character is composed of the normal character set, the user-defined set, or the crude pseudo-bitmap graphics.

Dithering is a possibility when converting images from high color and high resolution, but it can drastically increase the number of unique characters needed. Especially Floyd-Steinberg dithering will result in too much variation, so a flat pattern dithering is recommended. Personally I think dithering easily looks ugly so it is better used sparingly.

Dynamite Dan on the Panasonic?
Apart from the character display, the Panasonic graphics capabilities very much resemble the ZX Spectrum. Here is a mock-up made out of a screenshot grabbed from Dynamite Dan running on a Spectrum emulator and transferred to the Panasonic. Many 8-bit games make use of repetitive background graphics, so the limitation in the character set would not necessarily prevent making games similar to the Spectrum.

Accessing the screen and attribute memory

What follows is rather detailed information about character displays, using the Panasonic as an example. The character displays are blissfully simple to program, and it shows the kind of directness nowadays missing from computer programming. Fiddling around with the character memory is is also a neat visual way into understanding the workings of the old computers.

This will be painfully thorough, and is likely to be uninteresting to an expert!

A classic 8-bit computer has a bunch of memory that appears to the user as a series of address locations, like 65536 bytes. For convenience, the memory represents everything that is in some ways accessible to the user. Portion of this memory would be reserved for the video. Changing the contents of those memory addresses would have a direct effect on screen.

The Panasonic screen layout is at the memory positions ranging from $C100 to $C3FF. As the screen grid has 32 x 24 characters, this makes exactly 768 bytes. The attribute memory is located in positions between $C500-$C755, again 768 bytes. This indicates the colours for each of the 32 x 24 cells on screen.

What is visible on the Panasonic display is dictated by the contents of the screen memory, the attribute memory and the character graphics memory. The attribute memory and the screen memory are in clear correspondence with each other. For each cursor grid location on the screen there is a memory location in screen memory and the attribute memory. The character memory is from where the pixel patterns for the character are derived.

All the memory can of course be accessed from the BASIC. The POKE command is used to change memory contents, so...

POKE $C100,$41

...would result the character 'A' appearing at the top left corner of the screen, as this memory area is reserved for the screen memory. Furthermore,

POKE $C500,$16

...makes that character appear yellow on a red background.

The attribute memory contents dictate what colour the corresponding characters have on the screen. But there's more to it. Now, as each byte can denote a value of 0-255, this would mean the Panasonic can display 256 unique characters on screen. Yet because of the additional features in the attribute memory, it is possible to have more. The attribute cells not only determine the colour of the characters, but they tell how the screen memory contents will be interpreted.

Sadly, this does not mean there are 512 or 768 characters, as the practical number of additional characters is 64, making up the total of 320. This is likely because the video memory would have exceeded 4 kilobytes, something the computer designers apparently wanted to avoid. 

Defining the characters

$D000 begins the memory portion reserved for the appearance of the 256 standard characters themselves. As the characters are made from 8x8 pixel, each takes up eight bytes. 256 characters takes 2048 bytes of memory, or $800 in hex.

A detail of how the bitmap is divided into different characters. Each cell refers to a 8x8 pixel character and has its own attributes, background and foreground colour.
It's not granted that every computer that has character graphics has user-definable character graphics. For instance, Mattel Aquarius only has a fixed character set and no bitmap graphics. Defining the graphics is a matter of changing the memory contents in the reserved area.
So, again in BASIC,

POKE $D000,$FF

changes the first byte in the first character into $FF (255). This has an immediate visible effect on the Panasonic screen, as clear background is made up of this first character. The screen will be filled with horizontal lines. POKEing the location back to zero will rid of the line.

The following POKEs give a nice brick effect:

POKE $D000,$FF
POKE $D001,$4
POKE $D002,$4
POKE $D003,$4
POKE $D004,$FF
POKE $D005,$40
POKE $D006,$40
POKE $D007,$40

This is a bit painful. The classic way of inputting user defined graphics would be something like this:

10 FOR A=0 TO 7
30 POKE $D000+A,B
50 DATA $FF,$4,$4,$4,$FF,$40,$40,$40

Saturday, 11 February 2012

Panasonic JR200u tape wave generation

I've previously described the contents of a CJR file and the structuring of the Panasonic JR200U tape format. Here I'll go into converting binaries into WAV audio files that work as JR200 tape input. The purpose is to produce similar audio files as would result when an output from the actual machine is recorded. It's pretty straightforward except for the fact that the tape audio consists of data encoded both in 600 and 2400 baud speeds, and the way of encoding for the two is a bit different.

I'll take a very brutal and practical approach and merely tell how to construct a wave file that can be played back to the Panasonic from an audio software such as Audacity. This is just a crude task of appending bytes into a file in a correct order, and the finer points about signal processing can and will be ignored. First I will describe how bytes are composed in an audio file both in the 600 baud format and the 2400 baud format and how to append them into the WAV as waveform data points. Only after then the overall layout of the wave file with all the necessary "filler" will be given.

The following will work with the assumption that the file consists of a 600 baud header and 2400 baud data blocks. The logic of a full 600 baud file is slightly different, and simply using 600 baud binary with the below description will not work. For completeness sake, this may be addressed in the future, but as the 2400 baud format is the more useful the lower speed is ignored for now.

If you just need a tool for converting CJR files, head to this page.

The header bytes

Looking in detail at a tape audio wave in Audacity, it can be seen the data is encoded in a square wave.

This is the beginning of a header block after a lead in. A block in a normal file always seems to begin with a 2 and 42. (See the previous blog entry for the composition of the CJR files.)

The bytes are of course built out of bits, and these bits are represented in the header wave as a group of longer and shorter waves. The longer wavelength is 1 and the shorter is 0.

So, the above wave will translate into bits like this:


The highlighted parts are the same as are highlighted in the image above. The "nybbles" of 1110 are byte markers that precede all actual data bytes. They are not part of the stored data content. The lead-in and all in-between sounds are long series of 1's without the nybbles.

I have previously illustrated the composition of a byte in the header, and here it is again. The format is little-endian binary. This is the composition for the Ascii character 's' (Decimal 115):

The following byte marker actually belongs to the next byte already, which is not visible. Building the header as a wave with this information is then quite simple. For each data byte, the byte marker bits and the data bit waves are appended to the wave file.

But how many audio samples does each bit result in the actual wave file?

I'm assuming a 44100hz sample rate for the WAV, as to simplify the practical task of constructing the file. Note that what follows is not ideal, for reasons given later in the text.

This is the procedure for making the bits:

Do 0: Make the datapoints for a 0-bit:

Write 8 data points of negative signal
Write 1 data point of neutral signal
Write 8 data points of positive signal
Write 1 data point of neutral signal
Write 8 data points of negative signal
Write 1 data point of neutral signal
Write 8 data points of positive signal
Write 1 data point of neutral signal
Write 8 data points of negative signal
Write 1 data point of neutral signal
Write 8 data points of positive signal
Write 1 data point of neutral signal
Write 8 data points of negative signal
Write 1 data point of neutral signal
Write 8 data points of positive signal
Write 1 data point of neutral signal

Do 1: Make the datapoints for a 1-bit:

Write 17 data points of negative signal
Write 1 data point of neutral signal
Write 17 data points of positive signal
Write 1 data point of neutral signal
Write 17 data points of negative signal
Write 1 data point of neutral signal
Write 17 data points of positive signal
Write 1 data point of neutral signal

Both take 72 data points in the wave file. In an 8-bit wave, this would be the actual number of bytes, whereas in a 16-bit wave, the amount will be double. I have myself used 16-bit waves, although 8-bit (or even less) might suffice.

Just to reiterate the obvious, using the above logic the character 's' as in the previous image would be built like this:

Do 1, Do 1, Do 1, Do 0. [The byte marker nybble]
Do 1, Do 1, Do 0, Do 0, Do 1, Do 1, Do 1, Do 0. [The character 's' in ascii]

The 2400 baud format

The 2400 baud format is slightly more difficult to illustrate. When visualized, the bits are not a set of consistently identical peaks and valleys.

The above image is a portion of the wave where the data begins in 2400 baud format. The construction of the short and the long wave does not differ, but the data is 4 times more dense than in 600 baud format.

Although the image highlights the nybbles very clearly, it is not so obvious how the data bytes are composed. The image shows bytes 2 and 42 as before, but they don't look quite the same. So, the difference between 600 and 2400 baud format is not simply a question of changed frequency.

The data is there in the same little-endian way, it is just that the waves representing ones and zeroes can be "upside down". Let's have a visual look at one of the bytes, the 42.

The illustration already makes things much clearer. The first '1' within the byte points "down", whereas the second one points "up". Also, the three one's in the nybble point to alternate directions. But, looking at the two last zeroes, they are identical. So it is the '1' that changes the phase.

Both the above images are misleading in that the nybble byte markers seem identical. They can also be inverted, depending on the previous bit phase, it just happens so the chosen images do not show this.

To cut the explanation, here's the procedure for making the bits in a 2400 baud format:

(The A-signal is initially negative, as the last 1-bit in the 600 baud format part implies.)

Do 0: Make the datapoints for a 0-bit:

Write 8 data points of A-signal
Write 1 data point of neutral signal
Invert the A-signal
Write 8 data points of A-signal
Write 1 data point of neutral signal
Invert the A-signal

Do 1: Make the datapoints for a 1-bit:

Write 17 data points of A-signal
Write 1 data point of neutral signal
Invert the A-signal

So, how each bit "looks like" in the wave depends on what the state of A was after the previous bit was written. So unlike in the 600 baud format, the wave writer needs to keep record of this phase.

A note about the approach

This method as described will not generate precisely same overall wave file lengths as recorded from the Panasonic. Some adjustment may be required to achieve this. In reality, the wavelength is not "72 bytes" long, but a frequency. The described approach is in a way inferior to one where a real frequency is used. This method does work, though, so it will suffice here. Also, this procedural approach is simpler to explain.

In my wave generator, I added a global time skip variable that can be used to adjust the overall synchronization of the wave. The time skip can be adjusted so that the overall audio file lengths would better correspond with those of the actual machine. This means that data points are counted as they are written into the WAV, and each hundredth (say) will not be written. Or if the audio file needs to be lengthened, every hundredth data point will be written twice, or something like that.

The overall wave generation

The more tricky stuff has been gone through and what is left is to give the recipe for generating the whole audio file. For the content of the Blocks, refer to the previous blog post.

600 baud header:

 Generate some silence
 Lead in: More than 800 bits of 1
 Header Block: 33 bytes in the 600 baud format above
 In-Betweener: 51 bits of 1

2400 baud data blocks and footer/tail:

 Data Block 1
 In-betweener: 196 bits of 1
 Data Block 2
 In-betweener: 196 bits of 1
 Data Block 3
 In-betweener: 196 bits of 1
 Last Data Block
 A "long 1", See *1
 In-Betweener: 188 bits of 1
 Footer Block (tail)
 Byte 255, See *2
 Lead out: some 150 bits of 1
 Generate some silence (5 seconds between tape parts for example)

*1: The Long 1 is an anomalous piece of waveform that seems to be added at this point. It can be treated as a 1 that has twice as long waveform. I'm not sure if Panasonic really requires this, but it's better to be precise.
*2: The byte 255 is not included in a CJR file.

The above image shows the anomalous waveform near the end of a file, before the footer. Looking the image closer will also reveal the number of samples used for the waves. (36 as opposed to the 17 in the following wave.)

The WAV format

Describing the actual wave file format is really outside the scope of this post, but I'll include the bare description for writing 16-bit, one channel, 44100hz sound files. So, again, the following is just for the purposes of generating the things discussed above, and it is not intended to be a full WAV specification. The alphabetic values are in Ascii.

An easy formula for the entire file size [offset 4-7] is 44+seconds*88200.

0    : R
1    : I
2    : F
3    : F
4-7  : 32 bit value for the entire file size
8    : W
9    : A
10   : V
11   : E
12   : f
13   : m
14   : t
15   : 32 [space]
16   : 16 [16-bit pcm]
17   : 0
18   : 0
19   : 0
20   : 1 [audioformat=1]
21   : 0
22   : 1 [numchannels=mono]
23   : 0
24-27: 44100 [32-bit value for sample rate]
28-31: 88200 [32-bit value for byte rate]
32   : 2 [block alignment]
33   : 0
34   : 16 [bits per sample]
35   : 0
36   : d
37   : a
38   : t
39   : a
40-43: [32 bit value for the wave chunk size]
44-  : [16 bit words for the single channel wave data.]