Wednesday, 10 October 2012

The problem with while loops in PHP.

As a programmer who is rather fond of the language C, I tend to use a lot of while loops. These are great as in C one or more is true and zero is false, so if you are writing a simple Space Invaders clone, you would logically have a variable of type int called lives, so:

int lives = 3;
  

and in the game pump, you'd simply have:

void gamePump( void )
{
     while( lives )
     {
          // Do the game routines
     }
     gameOver();
}
  

So, when lives is zero, it'll call the routine or function or method you've called gameOver, and logically return to the title screen after that.

We can use the same logic with PHP, of course, but let's say this time we want to echo out an array of names. You'd do something like:

$names = array(
    'Dave',
    'Eric',
    'Zach',
    'Andrew',
    'Lisa',
    'Andrea',
    'Richard'
);
$index = 0;
while( $names[ $index ] ) {
     echo $names[ $index ] . PHP_EOL;
     $index++;
}
  

This will return an error, which is why the foreach command is there, so the same code in foreach would be:

$names = array(
    'Dave',
    'Eric',
    'Zach',
    'Andrew',
    'Lisa',
    'Andrea',
    'Richard'
);
foreach( $names as $name ) {
     echo $name . PHP_EOL;
}
  

Okay, so the error is solved. But if you wanted to use a while loop specifically, like in C, you'd have to null-terminate the array. In the top example above, you should:

$names = array(
    'Dave',
    'Eric',
    'Zach',
    'Andrew',
    'Lisa',
    'Andrea',
    'Richard',
    null
);
// etc...
  

This works fine if you don't want to sort the array alphabetically. If you do use the sort command, you'll need to use the foreach method above, as the first entry after a straight sort (key zero) will be null.

Monday, 24 September 2012

Octal.

If you've ever worked with machine code or assembly, or even C or C++, you will have come across binary and hexadecimal. Lesser-used number systems are binary coded decimal and octal. I've just had a quick discussion on Facebook, in which I quickly converted a number in hex into its' binary equivalent. This is easy to do, and when you know how, the same principles apply to converting a binary number to octal, although you group together every three bits, rather than every four.

But who uses octal anyway? I was asked by someone perhaps being a little complacent and because octal isn't commonly used any more by any programmer under the age of 40 (at a guess).

Not using octal doesn't present an immediate or obvious problem as most people work with decimal unless they have to use anything else. But what if you were interfacing with a database, calling a users phone number, for instance, and you cast it incorrectly? This is exactly what I did. I'll explain more about this in a mo, but first, let's look at hex and decimal.

Hex numbers begin with 0x (zero-x) and counts 0 - 15 for each place, for instance:

// 32-bit RGB value read as AARRGGBB
#define   COLOUR 0xff071dee

and with binary, you'd use a 0b prefix, and each place is either zero or one. Decimal is how you'd use it in the real world, with no leading character, but octal simply starts with 0 (zero), and here is where the problems can begin.

For those of you old enough, you may remember that, once upon a time, all telephone numbers started with zero. My area code was 0606. Inexplicably, British Telecom (as it was known at the time) changed this for no apparent reason to 01. Now, a friend of mine vented his frustrations about this. Why? What was the point? He enquired about this quite a lot, reporting back through his fanzine 8 Bit, as it seemed to be a change just for the sake of it, and no one was providing a good explanation.

Thinking back now and with the benefit of computer science-type study since, could it be that some computer systems were being tripped up by the leading zero, especially if the rest of the number looked like octal to some server somewhere? Imagine if you had a taxi business in the Greater London area, and chose a very easy to remember number like 071 777 7111. The octal value of this is very different to the decimal one, so adding the 1 immediately after the zero could have been an attempt at a remedy from it being automatically cast to octal and therefore showing a different decimal value after the casting. Well, maybe.

Could it also be now that all phone numbers start +44 nowadays because of this known problem?, especially as most mobile numbers start 07. Well, a couple of weeks ago, I was working with a young guy at Metapps on some PHP basics. He was doing a short works experience while in the local area, and was due to travel back to London soon, so we had to squeeze a lot into a short space of time.

In the task that we were working through, we were adding data entries to a database and calling it back. The example was someone's name, address and telephone number, and I put an example for the latter field of 07777777777, and called it back using some basic PHP code (well, inline SQL to be more exact), storing the retrieved data in a variable called $phoneNumber. PHP is very loosely typed and handles variables, as far as I can tell, very safely. There's really no need for leaky memory to be crashing a server, is there? But I had my C head on, and I cast the number to type int. When I echoed out the variable, I got a very strange result.

Luckily, the problem was quickly resolved by using the +44 prefix, and therefore dropping the leading zero. Remembering that I was using PHP, I also dropped the casting to type integer. I then went on to explain to the young 'un about how computers store numbers, and how compiled code and interpreters these 'scalar types' them from an area of memory, a file or a database, and how different prefixes can affect the value, with a leading zero being the prime example stating "this number is octal".

So, who uses octal anyway? Well, the question shouldn't be who, but what technologies use octal... and PHP, along with C and C++ are definitely included there, along with, I imagine, Java. Sometimes, it's good to know these things.

Thursday, 8 March 2012

6502 programming.

The latest issue of the excellent Commodore FREE is out (issue 59), and is available at www.commodorefree.com. In it is the second part of my 6502 programming tutorials that I wrote for Micro Mart (issue 58 has parts one to four, followed in this issue by five to eight), for those who may be interested in learning a bit of machine code on the Commodore 64.

I'm really pleased with the number of reads of my Z80 tutorials here, so hopefully this will prompt a similar number to read Commodore FREE perhaps for the first time. Feel free to ask any questions here (including code examples), and I'll do my best to answer you.

Tuesday, 21 February 2012

Introduction to Z80 assembly part III.

Here are the final four instalments of the Z80 assembly language tutorials that I wrote for Micro Mart magazine [now defunct] (www.micromart.co.uk) that were printed a couple of years ago now. Thanks for all of the kind comments about these articles here and elsewhere. Lets get on with it, shall we?

Return of the bedroom programmer

Part IX: Buzzer

You'll may recall from previous tutorials that we've spent a lot of time looking at how the screen works, and in the most recent part, there was the concept of the two 'channels' (of which there are three) used by the Sinclair ZX Spectrum to decide where to display or output your text. Other basic concepts have been gently introduced that will hopefully help you in building your project in the months to come, such as adding delays, moving bytes around and doing a basic keyboard scan. I know it has been at a rather sedate pace which may annoy some people, but the whole point is for those people who have been frustrated by assembly language tutorials in the past (including me) to try the now ancient art of programming at the machine's level. If you would like to move much quicker than this then please join the Spectrum Computing community forums at spectrumcomputing.co.uk/forums/ and look in the 'Development' sub-forums. If you're perfectly happy with this series so far then point your web browser at the Micro Mart forums (the specific thread is at tinyurl.com/Speccy-Coding a secret that only Archive.org can reveal) if you require help, but right now lets get coding.

This week, we'll move on to looking at the Speccy's infamous beeper. Don't worry to much about musical theory for now. Here is a quick example to play one note.

    org $8000       ; As usual, our code will
                    ; begin at 32768 (8*4096)
    ld hl,262       ; This is the pitch for
                    ; our note
    ld de,255       ; This will be the duration
                    ; it will play
    call 949        ; Play the note by calling
                    ; the relevant ROM routine
    ret             ; Return to BASIC
  

I'll apologies now because I'm delving into the world of mathematics again. If this isn't your strong point then don't worry about it, just concern yourself with the code and experiment, or use the built-in calculator on the 128K Spectrum.

As you can see from the above small routine, the pitch of the note that you want to play along with the duration it is to be played is set up using the register pairs hl and de respectively. On the Sinclair, when the beeper is accessed, all other processing is halted until the note has finished, but fortunately you are working in machine language rather than BASIC, which is many times quicker.

What you will need to know is the 'Hertz' value for the frequency of note that the beeper is to play, or more accurately 'emit'. This is the number of times the internal loudspeaker needs to be toggled each second to produce the desired pitch. This is your base line for working out each note:

  • Middle C is 261.63Hz
  • C# 277.18Hz
  • D 293.66Hz
  • D# 311.13Hz
  • E 329.63Hz
  • F 349.23Hz
  • F# 369.99Hz
  • G 392.00Hz
  • G# 415.30Hz
  • A 440.00Hz
  • A# 466.16Hzm
  • and finally B 493.88Hz

If you want to go an octave lower than this then you must halve the value, and to go an octave higher, it should be doubled.

So far, so good? Well, now comes the difficult bit. You've worked out what note or notes you want to hear, so now you need to calculate how long you should play it, remembering that the longer it is played, the less processor time you will have to do anything else. Lets say you want to play G for 0.2 seconds, well we look up the value of G and times that by 0.2, so we have 392.00*0.2, which equals 78.4. Now divide 437500 by 392.00 (the G note), which will give you 1116.07 (roughly). Now subtract 30.125 and you get approximately 1085.94, and round this to the nearest whole number, which is 1086. To put it another way, the register pair de is our duration, which is equal to Frequency*Seconds and hl is used for the pitch, which has an equation of 437500/Frequency-30.125. Each time, you should round to the nearest whole number, so in this instance, hl should be 1086 and de should be 78.

I urge you not to worry too much about this as it's fairly easy to accomplish simple sound effects for your project without doing much maths at all, but this certainly worth knowing so have a play and see if you can write a simple tune. See you next week.

Part X: A MOB

Let's be honest, most of you that have been following this series will have in the back of their minds creating a 'commercial-quality' game for the old Sinclair ZX Spectrum, using '100% machine code', and if you look at the software released for the 8-bit home computer, not just during the 1980s but to date, then the vast majority of it falls into this category. So, the most obvious thing to do is to draw, animate and control graphics. I've covered writing text to the screen fairly extensively, so with any luck you've had a program proclaiming that you are ace, or perhaps a similar message in a 'scrolly text'. Maybe you've played about with last weeks example too and played a tune along with your message. Now you can add to the mix some user defined graphics. Let's have a look at this little routine:

    org $9000       ; Our program will
                    ; start at 9*4096 (36864)
    ld hl,GFX       ; Points the HL register
                    ; at the area of memory
                    ; called GFX
    ld (23675),hl   ; Initialized system for
                    ; user defined graphics
    ld a,2          ; We want channel two
                    ; (upper screen)
    call 5633       ; Open channel two
                    ; (ie, write to screen)
    ld a,12
    ld (XCOORD),a   ; We'll put our graphic
                    ; character on row 12
LOOP
    call INITXY     ; This will set up the
                    ; X (row) and Y (column)
                    ; co-ordinates
    ld a,144
    rst 16          ; Display character 144 
                    ; (our UDG)
    call DELAY      ; Let's slow things down
                    ; a little
    ld hl,XCOORD    ; Get the current position
                    ; and store into HL
    dec (hl)        ; Decrease HL by one
    ld a,(XCOORD)   ; Store new co-ordinate
    cp 255          ; Is it at the top line
                    ; of the screen yet?
    jr nz,LOOP      ; If not, then jump
                    ; back to LOOP
    ret
DELAY
    ld b,12         ; Delay length
DELAYLOOP
    halt            ; Stop everything
                    ; temporarily
    djnz DELAYLOOP  ; Decrease B by one
                    ; and repeat until B
                    ; is zero
    ret
INITXY
    ld a,22
    rst 16          ; Calls the Sinclair
                    ; PRINT AT routine
    ld a,(XCOORD)   ; Gets the X co-ordinate
    rst 16
    ld a,(YCOORD)   ; and the Y co-ordinate
    rst 16          ; So, essentially
                    ; PRINT AT X,Y; like in BASIC
    ret
XCOORD
    defb 0
YCOORD
    defb 15
GFX
    defb %00111100
    defb %01011010
    defb %01111110
    defb %01011010
    defb %01100110
    defb %00111100
    defb %00000000
  

Once it's compiled, run it and see what happens. As you will notice, the redefined character cell is represented in binary at the end of the program, with each '1' representing the bits that are 'on', and '0' [the bits that] are off. There is a deliberate fault in the program though, which you will realise soon enough. How can this be fixed? And can you make your UDG travel on the horizontal and vertical plane, or start from a different part of the screen? How about replacing the delay routine with a piece of code that will play a note, or perhaps wait for a key to be pressed on the keyboard before continuing with the main routine? The more you experiment, the more you will learn, so now is a good time to get your hands dirty by trying to sellotape together previous examples with this one. Don't worry about errors as it's all part of the process.

If you would like some theory as to what is happening and why, then pop along to the Micro Mart forums (the specific thread is at tinyurl.com/Speccy-Coding), or leave any questions that you have here.

Part XI: Chunky chars

Before I proceed, I'd just like to mention one of the most useful sources of reference for any budding Sinclair ZX Spectrum programmer, and that's the original 'Sinclair ZX Spectrum BASIC Programming' manual that was bundled with the original rubber-clad machines. This has also been archived online if you want to search for it, but with the sheer amount of Spectrum's sold during the early years of the 8-bit, a physical copy shouldn't be difficult to source second hand. I don't know about you, but I prefer printed books over electronic versions.

If you refer to chapters 23 and 24, you'll find a rather handy keyboard and memory map. As you're using assembly, and not BASIC, you have direct control over the memory usage, within the limitations of the available 41K or so available to you (which is about 9K if you're trying to squeeze something into 16K).

Something else I've found very useful for programming is a pencil and paper, to draw a scheme of the whole project. Breaking down the program into logical steps and solving problems is what it's really all about. To do this, you may use traditional methods, like flow charts or pseudo-code. The former is good for small routines and the latter for bigger chunks of code. There is a new kid on the block too, which is Test Driven Development, in which you write a test first that will check if your code works to the bare minimum that you need it to do. This might seem counter-intuitiave as the test will automatically fail until you've written the code that you want, but prevents unnecessary programming and Keeps It Simple and Stupid (KISS), which should be easy to maintain. The trick is to find what works for you, especially for personal development like programming 8-bits.

Last time, we looked at moving a simple redefined character cell. We did this by changing the Sinclair's two-byte system variable at location 23675 to point specifically at our character cell, which was a smiley face if you entered the bianry correctly. You could have easily redefined your own UDG (User Defined Graphic, sometimes referred to as MOBs or Movable Object Blocks) if you wanted to.

From BASIC, you have 21 UDGs (or 19 on 128K machines, at least in the 128's native mode). You may change the system variable at 23675 for each sets of UDGs you define but although it's quite easy to implement, things can become quite messy.

You will have noticed that the routine left it's trail as it moved up the screen. This was the deliberate bug that I left in for you to sort out. To stop this from happening (if you haven't worked it out), you would need to write the character 32 (space) after calling the DELAY routine and before moving one row up, or something like this. Try it yourself to see what produces the best results, trying to avoid any annoying flickering along the way. Here is a routine that will copy the ROM font into another part of RAM and manipulated it to make it look chunky:

    org $9000       ; Our program will
                    ; start at 9*4096 (36864)
    ld hl,15616     ; HL will point at
                    ; the ROM char set
    ld de,60000     ; Here is were in RAM
                    ; we will store it
    ld bc,96*8      ; We have 96 chars
                    ; times 8 rows
NEWFONT
    ld a,(hl)           
    rrca            ; Here's something new,
                    ; it 'rotates' each bit
                    ; in the accumulator
    or (hl)         ; Logical or, which will
                    ; combine the two sets of
                    ; bits (non-rotated and
                    ; rotated right)
    ld (de),a       ; Store the new bits
                    ; into RAM
    inc hl
    inc de
    dec bc          ; bc is used as a
                    ; counter here
    ld a,b          ; get the high byte in
                    ; the register pair (b)
                    ; in bc
    or c            ; and combine with the
                    ; low byte (c)
    jr nz,NEWFONT   ; Repeat until bc is zero
    ld hl,60000-256 ; font minus 32*8
    ld (23606),hl   ; Point to new font
    ret
  

Part XII: And finally...

They say all good things come to an end, though whether this series has been good or not is up to you. This will be the last of the tutorials for the old Sinclair ZX Spectrum for now. I plan to move onto the 6502-based processor next (this is now available through the pages of Commodore FREE magazine at https://archive.org/details/commodorefree). Let's get straight into the coding then, have a look at this routine.

    org 32768       ; This is where we'll
                    ; start our program
    call PRINTINIT
    ld bc,10010
    call DISPNUM
    ld a,13
    rst $10
    ret
PRINTINIT
    ld a,2
    call 5633       ; open channel
                    ; two (upper screen)
    ld a,22
    rst $10
    ld a,0
    rst $10
    rst $10         ; This is equivalent
                    ; to PRINT AT 0,0;
    ld de,STRING
    ld bc,EOS-STRING; Length of STRING
                    ; to print
    call 8252       ; Throws our STRING
                    ; out via channel two
    ret
DISPNUM
    call 11563      ; We'll push the BC
                    ; register onto the
                    ; calculator stack
    call 11747      ; and then output that
                    ; number to the screen
                    ; by calling this routine
    ret
STRING 
    defb 83,127,111,114,101,$3a
EOS
    defb 0
  

Run it (with RANDOMIZE USR 32768) and see what happens. Basically, as the comments within the DISPNUM routine suggests, it's pushing the BC register onto the Sinclair calculator stack, then displaying that next to the last character printed. This allows whole integer numbers between zero and 65535, which once you run the code, you'll see its' intended usage. There are some drawbacks to this method, but for now it will be good enough.

Here's another routine to mull over.

    org 32768       ; This is where our
                    ; program begins in RAM
INFINITE            ; Our main marker
    ld bc,63486     ; Listen for keys
                    ; 1 to 5, also Sinclair
                    ; Joystick port 2
    in a,(c)        ; What key has been
                    ; pressed?
    rra             ; Rotates the accumulator
    push af         ; Preserves AF register
                    ; (most importantly the A bit)
    call nc,LEFT    ; If left is being pressed,
                    ; call relevant routine
    pop af          ; restore accumulator.
    rra             ; The process repeats to
                    ; see what other bits
                    ; have been set
    push af
    call nc,RIGHT 
    pop af
    rra   
    push af
    call nc,DOWN 
    pop af     
    rra        
    call nc,UP  
    jp INFINITE     ; Unconditional jump
                    ; back to repeat process
LEFT
    ld a,0
    out (254),a     ; Okay, so what happens here?
    ret
RIGHT
    ld a,2
    out (254),a     ; And here?
    ret
DOWN
    ld a,4
    out (254),a     ; etc...
    ret
UP
    ld a,6
    out (254),a
    ret
  

Well, you can guess from the comments we're doing here. If you have a Sinclair joystick interface, or an Amstrad-made Spectrum, connect a compatible joystick (which can be emulated too) and see what happens. Checking for the fire button is missing, but I didn't want to make it too easy for you. Well, that's all for now, but it need not end here as the Micro Mart forums Spectrum Computing Development Forums are always open. Before I go, I think there's just enough space to thank Bob Smith and Jonathan Cauldwell for their help over the series, as well as everyone who endured it!

Monday, 23 January 2012

Shoot.

It's funny how things turn out sometimes. I had what I thought would be a good, solid game concept and tried to implement it on a Sinclair ZX81 in 16K, and, well it was a little bit more dull than I imagined it, but then as I was using the z88dk again, there were some compromises that I had to make mostly due to speed. Too much on the screen would have made proceedings too slow and boring anyway, so I decided to limit the maximum number of ships in a convoy, bombs and bullets. I also made the screen smaller and set a limit to the distance that each bullet will travel on the X and Y plane. I'm sure any pure Z80 coders could make a better implementation.

It's available from the RWAP Software website, and the source code is on pastebin here. Any comments, questions or feedback is welcome.

Tuesday, 10 January 2012

Bouncing into the New Year.

Over the past week or so, I've been playing around with C and the z88dk (z80 development kit), and I've finally got something stable enough to run on an emulated Sinclair ZX81 +16K, which I released yesterday and can be downloaded from here - I recommend the EightyOne emulator (just search for it). If you want to see the source code, a partially commented version is posted on pastebin. Bounce is freeware, by the way.

The great thing about programming for a limited platform - and they don't come much more limited than the old ZX81 now, do they? - is that it forces you to focus on the gameplay as the graphical capabilities don't really exist, and there's no sound chip or anything fancy. So, I think I have developed a fun but simple game (with Bounce) in no time at all really, and one that would work well on a portable device, such as a smart phone or something similar, as simple games work well to relieve the boredom of travelling. As the source is in C, this makes all of the logic very portable too!

Well, what next? I think I might do a shooty thing.

Thursday, 5 January 2012

Introduction to Z80 assembly part II.

Due to popular demand (well, by my standards), here's the second instalment of my exciting 'Return of the Bedroom Programmer' series that I wrote for Micro Mart magazine in the Summer of 2010. Part one is here: Introduction to Z80 assembly part I so if you've missed it, please read through. Note that this is only intended as a guide for beginners and not intermediate or advanced programmers.

Return of the bedroom programmer

Part V: More on Colour

Before we delve into the code, let's quickly recap on where we are up to (see the above link if needed). We've briefly looked at what the Sinclair ZX Spectrum was capable of, and how much RAM is available on the different models. RAM is important because the more of it we have, the bigger our program can be and, in many ways, the more we can do.

You should now be proficient at writing to the screen as what we've been doing in our code is defining an area of memory (called 'STRING'), putting some text there and then reading each byte into the accumulator (a) and outputting that to the screen using the Sinclair ROM 'PRINT' routine (by rst $10). If you look back on the examples, you'll notice that at the end of the text was two values, 13 is a new line (or carriage return) and zero was the marker for the end of the text. When you get into more advanced programming, you may want to know that using rst $10 affects the af register, but for now, this is not going to concern us.

In the last part of the first instalment, we looked at how the colour attribute worked for each character cell and I set you a challenge to change the colours in the code. To do this, you need to change the values of 'a' (the accumulator) before you store it at 23693 and call 3503, and [for the border] change 'a' before calling 8859. If you wanted 'BRIGHT' red text on white 'PAPER' without 'FLASH', the equation would be (0x128)+(1x64)+(7x8)+2, or 122. If you wanted to set the 'FLASH', then you would add 128 to this, totalling 250. Deducting 64 will turn off 'BRIGHT'. As for the border, it can only be one of eight colours, so simply 'load a' with the corresponding colour from zero to seven before you call 8859.

Of course, because we clear the screen by calling 3503, anything you set will then be the default value for the text area, therefore if you have set the 'FLASH' value then everything you see will flash.

Writing directly to the colour RAM is a better way of doing things, especially if you're having different areas of the screen using the various possibilities available. This area of memory is mapped at 22528 to 23296, with each byte holding the colour information to the corresponding 8x8 character cell. The colour RAM is therefore 768 bytes in total.

Let's say we want the first row to flash and the second row not to, here's a quick example:

COLRAM equ 22528
    org $8000     ; We'll start our program at
    			  ; 8x4096, or 32768
    ld de,COLRAM  ; Let's point the register de
                  ; at the start of the colour RAM
    ld a,129      ; Flash on, blue text on a
                  ; black background
    ld h,32       ; We'll use the register h for
                  ; a counter
LINE1
    ld (TEMP),a   ; Temporarily store a
    ld (de),a     ; Store a at location bc
    inc de        ; Increase de by one
    dec h         ; Decrease h by one
    ld a,h        ; Transfer h to a
    cp 0          ; Compare a to zero
    jr z,NEXTROW  ; Go to NEXTROW when a is zero
    ld a,(TEMP)   ; Get a back from TEMP
    jr LINE1      ; Jump to LINE1
NEXTROW
    ld a,80       ; Flash off, Bright on, red
                  ; paper, black text
    ld h,32       ; h is a counter again
LINE2
    ld (TEMP),a   ; Temporarily store a
    ld (de),a     ; Store a at location de
    inc de        ; Increase de by one
    dec h         ; Decrease h by one
    ld a,h        ; Transfer h to a
    cp 0          ; Compare a to zero
    jr z,BACK     ; Jump to BACK when a is zero
    ld a,(TEMP)   ; Get a from TEMP
    jr LINE2      ; Jump to LINE2
BACK
    ret           ; Return to BASIC
TEMP
    defb %11111111; Temporary storage area for a
  

Two things to note: firstly, the program will be stored at 32768, so it will not work on a 16K machine unless you relocate it. Secondly, it's a rather linear and inefficient way of doing things. As you progress, you'll want to be as efficient as possible, which will free up more memory for you. Think about this for a moment, as this is your next challenge: you could set some parameters (de and h) and then call this as a sub-routine from your main code. This will free up some memory for you and make your source code tidier at the same time.

Part VI: The screen

If you've been paying attention to these tutorials then you'll have started to develop a fairly good understanding of how the screen works, especially the colour attribute cells and where each is mapped in memory and how that corresponds the the character cell. Think of the screen as having two layers, the pixels and the colour attributes, if that helps.

If you're following this as I intended, I set you a challenge in part five to alter the example so that you could 'call' a subroutine from the main routine, and gave you a hint as to how this could happen. I think the answer is archived at tinyurl.com/Speccy-Coding, but feel free to ask here if you're struggling.

You now know how to colour in each character cell on the old Spectrum (which comprises of 8 x 8 pixels), but we've only touched on writing to the screen using the handy ROM routine. As you may recall, the screen RAM starts at 16,384, and each byte represents eight pixels in a row. The screen's resolution is 256 pixels across by 192 down (referred to as 'scan-lines'). You therefore have 32 bytes per scan-line, 192 times, meaning that the screen takes up a massive 6,144 bytes in total, or 6K out of the 48 available. The screen RAM ends at location 22527, with the colour attributes taking another 768 bytes after that.

What I found interesting about the Spectrum is how the screen RAM (excluding colour attribute) is mapped. If you haven't seen how the loading screen is drawn, or at least not seen one recently, then do so as that is exactly how the memory relates to the pixels on the screen. To demonstrate this more clearly, type in the following BASIC (not assembly) program to your Speccy or emulator and RUN it:

    1 LET a=16384 : REM Start of screen RAM
    2 POKE a , BIN 10101010 : IF INKEY$ = ""
        THEN PAUSE 4e4
    3 IF INKEY$ = "n" THEN PRINT AT 0 , 0 ; a
    4 LET a=a+1 : IF a = 22528 THEN STOP
    5 GO TO 2
  

Hold down any key and the screen should draw the bit pattern defined after POKE a in line 2 to the screen. You can try changing this bit pattern and see what happens. If you want to find out where exactly you are in RAM then press n at any time. The screen isn't mapped in a linear or logical manner, is it? Or is it?

As you will notice, the screen is drawn in three zones, starting at 16,384 to 18,431 (zone zero), representing the first 32 x 8 character cells (rows zero to seven), or 256 pixels by 64 scan-lines, and so 18,432 to 20,479 is the next 32 x 8 cells, and 20,480 to 22,527 is the final zone. In the Spectrum's memory, a binary representation of this is: 010B BSSS LLLC CCCC, worked out as follows:

  • BB = Block (zones 0-2), being either the top third, middle third or bottom third of the screen.
  • SSS = Scan-line (0-7), which relates to the vertical row in the character cell.
  • LLL = Vertical character line (0-7) within the block.
  • CCCCC = Horizontal character co-ordinates (0-31).

There is a short-hand way of working this out, as follows:

PRINT 16384+(x0*32)+x1+(y+(z*7)*256)

What this means is that if you're in zone zero (the first third of the screen), then x0 must be between zero and seven and z must also be zero, and the range for the scan-line (y) in each character cell is zero to seven, with x1 representing the column from zero to 31. This might be a lot to take in, especially if you're rubbish at maths like me.

In BASIC, we're only able to 'PRINT AT' to row 21 in BASIC, so with this in mind, here is another demonstrate:

    1 REM Change the parameters by
        the following:
    2 REM zone zero : x0=0 to 7, z1=0
    3 REM zone one  : x0=8 to 15, z1=1
    4 REM zone two  : x0=16 to 21, z1=2
    5 CLS : LET x0 = 0 : LET x1 = 1 : LET z1 = 0
    6 FOR z = (7*b) TO ((7*b)+7) :
        POKE (16384)+(x*32)+(x1)+(z*256),255
    7 NEXT z : PAUSE 4e4
    8 PRINT AT x,y ; FLASH 1 ; " " : PAUSE 4e4
  

I remember being totally confused by the memory lay out of the screen when I first wrote these tutorials, so I hope that these BASIC examples have helped. Thankfully, our saviour comes in the form of the Sinclair ROM as this will handle everything for us. Give your brain a rest for a while and make a refreshing cup of tea* before continuing.

* Coffee and other refreshments also available.

Part VII: Pushing and popping

I bet you're really getting to grips with programming the Sinclair ZX Spectrum, aren't you? That game you've always wanted to create, boasting 100% machine code on the cassette label can't be far away now, and I hope you're having fun along the way.

One thing you will have noticed is that most of the routines that have appeared so far have used the accumulator (a) and a register pair (bc or de, for instance). You've then typically stored bytes into the accumulator, to set a colour attribute cell directly in RAM, or to write characters to the screen. As we use the registers and the accumulator so often (in fact, we couldn't do much without them), you may occasionally need to temporarily store value, write a new value to do something else, and then restore the old one again. There are two instructions called 'push' and 'pop' which will do this for you, but only work with register pairs. Here's a quick example with the bc register:

    org $8000       ; Code begins at 8*4096
    ld bc,DATA1     ; Point bc at DATA1
    ld a,(bc)       ; Put it into the Accumulator
    push bc         ; Temporarily stores bc
    ld bc,DATA2     ; New value for bc (DATA2)
    ld (bc),a       ; Overwrites first byte in DATA2
    pop bc          ; Restore bc to old value
    ret             ; Return to BASIC
DATA1
    defb 0          ; zero not '0'
DATA2
    defb 255
  

What it's doing is storing the byte at DATA1 into the accumulator, pushing bc to the stack before pointing it at DATA2, writing the accumulator there and then restoring the old value to bc before exiting to BASIC. The assembler will make the two bytes at DATA1 and DATA2 read zero and 255 respectively. After executing the routine, they will both be zero. You can see for yourself by PEEKing at the memory locations from BASIC or using a disassembler or monitor from your emulator.

If we needed to temporarily store the accumulator (or any unpaired register) we can't use push, but we can declare a single byte of memory in our program as TEMP and put a null byte there; ld (TEMPA),a will save the value, which is then restored by ld a,(TEMPA). Here's an example of this in action (you may want to set your own colours and clear the screen first):

    org $8000     ; Store our program at 8*4096
INFINITE
    ld a,22       ; 22 is the Sinclair ROM value
                  ; for PRINT AT
    rst $10       ; Call the ROM PRINT routine
    ld a,0        ; We need an x and y co-ord for
                  ; PRINT AT, so a=0
    rst $10
    rst $10       ; We call it twice
                  ; (PRINT AT 0,0;)
    ld bc,STRING  ; Points the register bc
                  ; to STRING
LOOP
    ld a,(bc)     ; Puts the current byte at bc
                  ; into a
    cp 0          ; Compares a to zero
    jr z,MOVEBYTE ; If equal to zero, jump to
                  ; MOVEBYTE
    rst $10       ; Outputs a to the screen
    inc bc        ; Increases bc by one
    jr LOOP       ; Goes back to LOOP
MOVEBYTE
    ld bc,STRING  ; Let's point bc at the start
                  ; of STRING again
    ld de,TEMP    ; And de at TEMP, one byte
                  ; before STRING
    ld a,(bc)     ; Get the first byte at bc and
                  ; put into a
    ld (de),a     ; Store a at TEMP
SCROLL
    inc bc        ; Increase bc by one
    inc de        ; Increase de by one
    ld a,(bc)     ; Get the current byte at bc,
                  ; store in a
    cp 0          ; Compare to zero
    jr z,AGAIN    ; We'll jump to AGAIN if a=0
    ld (de),a     ; Store a at de (one byte
                  ; before bc)
    jr SCROLL     ; Jumps to SCROLL
AGAIN
    ld a,(TEMP)   ; a=TEMP
    ld (de),a     ; Store a at location de
                  ; (end of STRING before zero)
    ld b,8        ; Now we're using the b register
DELAY
    halt          ; Stop everything temporarily
    djnz DELAY    ; Counts down b register until zero
    jr INFINITE   ; Jump back to INFINITE
TEMP
    defb %11111111; byte used in MOVEBYTE and AGAIN
STRING
    defb " Micro Mart Rulez! "
                  ; 32 characters in total
    defb 0        ; End of string
  

I'll let you find out what this routine does (a hint is in the labels though). The challenge for this instalment was at tinyurl.com/Speccy-Coding, though you'll have to plough through and find it.

Part VIII: Changing channels

Those of you who tried last week's main routine will have noticed two things: firstly, it was moving the bytes about to do what was once called a 'scrolly text' (now referred to as an 'animated marquee'), and secondly it introduced a rather handy delay routine. Even though the Z80 inside the Sinclair ZX Spectrum is 'only' clocked at around 3.5Mhz (by today's standards, this is nothing), you may still need to slow things down a little sometimes. Additionally, if you ran the routine with PRINT USR 32768, it will have scrolled on the top line of the screen, whereas if you used RANDOMIZE USR 32768 then it would have appeared on the next to last row unless you set your own default colours and cleared the screen first.

As I have said previously, the Spectrum's screen is mapped logically in memory in three zones, but the Sinclar ROM sees it as two channels. The lower two rows of text are usually reserved for BASIC entries, and the 'user' screen is therefore everything above that. Of course, you can write anywhere to the screen by storing the relevant bytes you like, bypassing the ROM entirely, but this requires some maths as demonstrated above.

Thankfully, the boffins at Sinclair were kind enough to allow us to select what part of the screen we're writing to, and here's a quick example:

    ORG $8000     ; Put the program into
                  ; 8*4096 (32768)
    ld a,2        ; 2 opens the channel for
                  ; the upper screen
    call MAIN     ; Let's call the main sub-routine
    ld a,1        ; Okay, now we want to write to
                  ; the BASIC area
    call MAIN     ; Let's write some text again
    ld hl,23560   ; This is part of the keyboard buffer
    ld (hl),0     ; We'll clear it
LOOP
    ld a,(hl)     ; Put the current value of
                  ; hl into a
    cp 0          ; Compare it to zero
    jr z,LOOP     ; If equal to zero, go back
                  ; to loop
    ret           ; Key pressed, so return to BASIC
MAIN
    call 5633     ; Open channel set
                  ; by accumulator
    ld de,STRING  ; Point de to the start of
                  ; the STRING data
    ld bc,EOS-STRING
                  ; Tells the program how long
                  ; the STRING data is
    call 8252     ; Print the STRING out to the
                  ;selected screen channel
    ret           ; Return from sub-routine
STRING            ; Here's the string data
    defb "http://www.micromart.co.uk/"
EOS
    defb 0
  

Okay, so that's a bit different to how we've been doing things, and you may notice that we've got a fairly rudimentary keyboard reader in there too, like using PAUSE 4e4 in BASIC when you tell the user to "Press the any key" or something similar.

What's happening by calling 5633 is telling the ROM where to write the text to; channel two is for the upper area of the screen, channel one is for the lowest two lines of text, and there's also a channel three for the Sinclair printer too, should you ever need to use it.

The register pairs de and bc are then telling the routine at 8252 where in memory the data is to 'write' to the currently open channel, (de is the start of memory, and bc is the end). You'll notice that the text is written to the very bottom line for channel one, so have a think about pushing it up one line.

This technique is very handy as it uses a small amount of code. It's time for a break again. Keep on coding over the next few weeks until I sort out the final exciting* instalment.

* It might not be that exciting.

Monday, 2 January 2012

Starting with C

What starts with C and works on the Sinclair ZX Spectrum? Well, thanks to z88dk - available from z88dk.org - it's C.

I've been playing around with this and, I have to say, the Wiki is useful but not very helpful, and I can't find many clear examples that'd be good for beginners to get their teeth into. This, in my opinion, is due to lack of good commenting in the source code examples, and also it being written by many technically minded people who forget that sometimes things need to be explained in English, which is a language that I'm quite fond of as it can be very clear and concise if used well. So, I intend to write a beginners guide to C programming for the ZX Spectrum in the near future.

Anyway, after scratching my head for a few hours, I wrote a simple 'Hello World!' type program. This isn't a challenge, of course, but I wanted to change the colours of the text and bypass the 64-column mode which is what the z88dk compiler defaults to when you use it. I also got it to drop down to assembly for a short routine which sets up the default colours for the whole screen. Anyway, more importantly, I've commented it quite well so even if you're a complete novice at programming and would struggle with something simple, it should be straight forward enough. Note that there is a much simpler way to do the same thing, but simple doesn't always tell you everything that you need to know. Oh, and it also uses a look-up table, something that I always find myself building even if it's not always strictly necessary.

Here's the code:

/**
 * This does something similar
 * to the classic "Hello World!"
 * code that's a popular starting
 * point for learning programming.
 */
#include <stdio.h>

// Here are our default colour
// attributes
#define INK     7
#define PAP     2
#define FLA     0
#define BRI     1
#define INV     0
#define BOR     5

// This is used in the setup function,
// which drops into machine code -
// see my blog for more information:
#define COL     128*FLA+64*BRI+8*PAP+INK

// Forward declarations of functions:
static void main(void);
static void setup(void);
static void hello(void);
static void magazine(void);

// Global variables:
static int i=0;

// Here is an array which will set up
// the default colour attributes for
// printing our message to the screen,
// 255 is used as a 'terminator' to
// say "we've finished here"
static int screensetup[]=
{
     1, 32, 16, 48+INK, 17, 48+PAP,
     18, 48+FLA, 19, BRI, 20, 48+INV,
     12, 255
};

/**
 * This is the 'entry point' of our program:
 */
void main(void)
{
     // This will call a routine to
     // set the default colour
     // arrtibutes for the whole screen
     // as defined above:
     setup();
     // This does the same for outputting
     // out character see
     // http://www.z88dk.org/wiki/doku.php?id=platform:zx
     // for more information under the
     // heading "The standard ZX Spectrum
     // console driver" - hopefully, these
     // numbers will now make more sense!
     while(screensetup[i] != 255)
     {
          // The %c means 'print character code'
          // or something similar
          printf("%c",screensetup[i]);
          // Increase i to read the next element
          // of the array:
          i = i + 1;
     }
     // Calls our functions, firstly hello:
     hello();
     // and now magazine:
     magazine();
}

/**
 * This function sets up the default colours
 * for our screen as defined above:
 */
void setup(void)
{
     #asm
     // Sets default ink and paper colour,
     // then clears screen
     ld a,COL
     ld (23693),a
     call 3503
     // Sets border colour
     ld a,BOR
     call 8859
     #endasm
}

void hello(void)
{
     // Here is where the magic happens,
     // can you tell what it does?
     printf("Hello ");
}

void magazine(void)
{
     // And what about this bad boy then?
     printf("Magazine!\n");
}
  

Call the source code "HelloMagazine.c" (obviously without the quotation marks) and place it in the same directory as the z88dk 'bin' folder, go to your command line prompt and compile it with:

zcc +zx -lndos -create-app -o hello HelloMagazine.c

it should create a file called "hello.tap", simply load this into your emulator and watch with amazement as the magic actually happens!

PS, I'm certainly not endorsing any printed-matter publication which has all of the latest celeb goss or whatever - it's a joke as I've read too many times about "Hello World!" being the default starting point, so I always try to avoid it.