Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Monday, 13 March 2023

Learning Assembly and Hello World.

Hello World takes 30 lines of assembly?

Recently, I saw a programming meme on the BookFace so-called Social Media platform. It read "Ok ima Learn Assembly [sic] Damn Hello World is 30 lines" with an accompanying boxer first ready to fight, and then the said boxer taking a break with a water bottle.

Cards on the table, I am not a professional in any assembly language. I would say that I am most knowledgeable in Z80, and know enough in 6502 and MIPs to get by. And because I've not done any Z80 for a while (nor any other assembly for that matter), I'm a bit rusty with it. But I couldn't think how in Z80, or in 6502, or in MIPs, a Hello World program would take 30 lines of assembly. It may take 30 bytes, or words, but that's not the same. If you were learning assembly, you wouldn't be entering a program byte by byte (or word by word). That wasn't even a good idea 35 years ago.

So sure was I about this that I posted an example in 6502 with the target platform being the Commodore C64. My first try, although flawed, was 7 lines of assembly and 12 bytes of data. Whilst it worked fine to output 'HELLO WORLD' to the C64 screen (at 1024), it had a flaw that I didn't realise (as I didn't test the code before I posted it). It was only after testing that I realised the mistake, and posted a follow up which corrected my initial bug.

Some notes before I continue. For this example, I am using an online assembler found at nurpax.github.io/c64jasm-browser but other assemblers are available; if you want to try these examples on real hardware then I would recommend Turbo Macro Pro - some examples of how to use this are shown on Robin Harbron's excellent 8 Bit Show and Tell Youtube channel here. I recommend Robin's tutorials as he goes in to way more depth than I will be here.

Let's start from the dumbest example and work through it. In doing so, we may discover the elusive 30 lines of code issue highlighted by the meme.

* = $c000 ; Start address, call with
          ; SYS 49152 from C64 BASIC
    lda #$48 ; 'H'
    jsr $ffd2 ; Kernal CHROUT call
    lda #$45 ; 'E'
    jsr $ffd2
    lda #$4c ; 'L'
    jsr $ffd3
    lda #$4c ; 'L'
    jsr $ffd2
    lda #$4f ; 'O'
    jsr $ffd2
    lda #$20 ; ' '
    jsr $ffd2
    lda #$57 ; 'W'
    jsr $ffd2
    lda #$4f ; 'O'
    jsr $ffd2
    lda #$52 ; 'R'
    jsr $ffd2
    lda #$4c ; 'L'
    jsr $ffd2
    lda #$44 ; 'D'
    jsr $ffd2
    rts
  

As already stated, this is a dumb example, and we get to 24 lines.

It is using the C64 Kernal to output each character to the screen, so whilst this has some advantages, in that when you call this with SYS 49152 it will output from the next cursor position, and your code returns you back to BASIC cleanly on the rts instruction, it isn't necessarily the best way to do things. As an aside, this will also work on other Commodore machines, certainly the VIC-20 and C128 in native mode, and probably all other Commodore 8-bits including the PET as long as you relocate the code to somewhere where there is free memory available to store it.

Using the Kernal may be slower than handling things yourself, and using the CHROUT in particular means that you cannot easily write to the whole screen, as when you get to the last screen position (on the C64 this is 2023, or $07e7 in hexadecimal) and output there with a jsr $ffd2, your screen will scroll either one or two lines, and therefore the top one or two lines will disappear. If you limited your text to 999 characters maximum, or outputted to a specific screen area then this might be useful, but you'd also have to use the Kernal to position the cursor correctly before writing to the screen, which again may be cumbersome in some instances.

A more pertinent point here is that if you were actually going to learn assembly, you would not write any assembly like this. Aside from the relative slowness of calling to the Kernal CHROUT, you also have repeating code as almost every other line is a jsr $ffd2, and one of the lda instructions is not necessary at all. In the above example, it loads the 'L' character in HELLO twice before calling the CHROUT routine twice; a small efficiency here is to simply load the L character value once and call the CHROUT routine twice. But even then, doing things this way isn't how you would learn assembly. In assembly, you would set up a conditional loop to read from an area in memory where each byte of the data is stored with your message (HELLO WORLD), and then iterate the loop until your condition to terminate it is met, and output each byte to your display. Based on the CHROUT example above, let's have a look how one might do this.

* = $c000
    lda #$00 ; Set Accumulator to zero
    ldx #$00 ; Set the X register to zero
    lda $c01b,x ; Start of loop, reads the
                ;data to the Xth byte
    cmp #$00 ; Have we hit our terminator yet?
    beq *+9 ; If so, branch ahead 9 bytes
    jsr $ffd2 ; CHROUT
    inx ; Increment the X index
    jmp $c004 ; Jump back to the start of our loop
    rts ; Return to BASIC
* = $c01b ; Data at $c01b
    ; The data is split into multiple lines as
    ; putting it on a single line does not work
    ; well on the Blogger platform as the text
    ; overflows the design boundary and looks ugly
    !byte $48, $45, $4c, $4c
    !byte $4f, $20, $57, $4f
    !byte $52, $4c, $44, 0
  

Now that looks better, and we're definitely not near the 30 lines supposed in the meme, more like 12 if the data bytes are written on a single line.

A few cautionary notes here. Firstly, whilst I am not using labels, they are very useful and make your development easier to manage, and allows any assembly program room to grow, as the labels will move as your code gets longer or shorter. I don't use them as the online assembler linked above gives me an instant disassembly of the program as I type it, so I am able to correct my assembly code as necessary. But for convenience, I have set the start of the code to $c000 (SYS 49152 as already mentioned), and the data to be stored from $c01b.

We have a much nicer example now, but there are still some things to improve: firstly, we have at least one line of unnecessary assembly: cmp #$00. This means we want to compare an absolute value (zero) with the current value in the Accumulator (A). Before this comparison we have loaded a value into A with lda $c01b,x. This is taking a byte from memory location $c01b offset by the current value of X. On our first iteration, this takes in the value $48, as the X register is zero, and therefore so is the offset. Our comparison is false, and the beq *+9 (branch if equals +9 bytes) does not happen. We then increment the X register with inx and jump back to the start of the loop with jmp $c004. And so the next iteration will load A from memory location $c01b offset by 1, and so on until X is 11 and our zero terminator condition is met. And once the condition is met, it branches 9 bytes ahead to the rts instruction, returning back to BASIC.

You may add more PETSCII bytes to the data block from $c01b as long as you don't have more than 255 bytes of data in the block including the zero terminator. For reference, the C64 character codes are here.

We are explicitly comparing the current memory contents to a zero value; in 6502 we don't need to do this. This is because when loading a value into the Accumulator, either directly, or by reading a memory address, it will set the zero flag if A happens to be zero. As the zero flag is set, we may do a $beq *+9 without the preceding cmp #$00 because a branch instruction will test against the zero flag unless you explicitly tell it not to. If our terminator had a value of 255 ($ff in hexadecimal), we would need to do a cmp #$ff statement before the branch instruction. By using an absolute value of zero as a terminator, we have saved one line of assembly, and two bytes.

This isn't the only improvement that we may make here; at the start of our example above, we load the Accumulator with an absolute value of zero (lda #$00), and then do the same with the X register. But to save another two bytes, we don't need to initialise A to zero; we only need to initialise the X register to zero as that is being used as our offset. As we have saved two byte, the jmp $c004 needs repointing as the start of the loop has moved up in memory by two byte. With these improvements, let's have a look at our new assembly listing.

* = $c000
    ldx #$00
    lda $c01b,x
    beq *+9
    jsr $ffd2
    inx
    jmp $c002
    rts
* = $c01b 
    !byte $48, $45, $4c, $4c
    !byte $4f, $20, $57, $4f
    !byte $52, $4c, $44, 0
  

Surely now we're done. The code itself is now pretty efficient. But we can still save one byte in our main loop. Remember that the zero flag is set if you write something to the Accumulator that equates to zero? The same principle applies to the X and Y registers. After we call the CHROUT routine with jsr $ffd2, we then increment the value in X with inx. The first time this happens, X will of course hold a value of 1, and we know that X will never be zero as we only have 12 data bytes including the terminator. This means that the zero flag is never set by the X register in our example, so we may use the branch instruction again instead of jmp $c002. It is only possible to branch 127 bytes back in your code, or 128 bytes forward in your code. Our code is small, and the loop beginning at $c002 will only be 9 bytes back from a branch if not equals instruction that we're adding. This saves one more byte from our code! Therefore, our rts line, to get us back to BASIC, is one byte lower in memory and the beq *+9 needs repointing too. Let's have a look at our final version with this optimisation:

* = $c000
    ldx #$00
    lda $c01b,x
    beq *+8
    jsr $ffd2
    inx
    bne *-9 ; We know that the zero flag
            ; is not set as we have incremented
            ; the X register by 1 and also we
            ; are not reading in 256 bytes of data.
            ; When the X register is 255 ($ff) and
            ; is incremented, it wraps around to
            ; zero. This same rules apply to
            ; the Y register.
    rts
* = $c01b 
    !byte $48, $45, $4c, $4c
    !byte $4f, $20, $57, $4f
    !byte $52, $4c, $44, 0
  

So there you go, we have a small and efficient hello world example in assembly, starting from a dumb example. I was going to go onto writing this to screen RAM at $0400 hexadecimal, or 1024 decimal, but this blog post is already long enough just covering the points that I wanted to, so I'll leave writing directly to the screen RAM for my next blogger update.

Thanks to Robin of 8 Bit Show and Tell mentioned above, and the other feedback I got from Mastodon. I received some very helpful comments about this blog post which has improved it. Note that we are able to make small and tight loops like this on the C64 with the CHROUT Kernal routine because this call preserves the Accumulator, X and Y values for us. Other Kernal calls may not do this, and will therefore require additional logic to track these values. But this is for a future blog. I've enjoyed re-acquainting myself with some 6502 again, and I'm glad it makes more sense now than it did the last time I looked at it.

If you don't want to wait for the next update, a really good C64 resource is available here, and there are plenty of 6502 resources just a few clicks away.

Sunday, 4 December 2022

What advice would I give newer and junior developers?

Over 10 years ago, I began a career transfer from an adult support worker (or whatever that role is called now, a care assistant in old money) to one in Computer Science. I knew on beginning my Degree in Enterprise Computing, a programme that I attended thanks to Manchester Metropolitan University (MMU), that what I wanted to do with the rest of my life was software development. Through the course, I discovered that my two best classes were Programming, and Business Studies and management. My least favourite and consistently poor results fell into the Database and Structured Query Language (SQL) side of things.

Whilst I kept writing through University and beyond (exclusively through the pages of Micro Mart at that point), it became very obvious that in order to progress as a developer, [software development] had to be the main focus in my life, so writing became much less important to me. I had a good technical grounding in programming languages thanks to MMU but especially due to an unexpected almost full year at the University of Derby Games Programming course (this was due to Government funding cuts thanks to a certain coalition of chaos that I won't mention further).

At Derby I had covered a lot of C and Visual C++, some MIPs, Java for Android and some other languages. Being focused on entertainment rather than application software meant a whole lot more programming but no database theory, management or SQL. I did make the point that SQL will become more important even in the games programming world, something that at least one of my lecturers acknowledged. How else are you going to store all of that data for all of those online games?

Anyway, I started as an web application developer thanks to an Internship. After about one year, I had my first job proper at a company in Wolverhampton. I was taken on as a Junior Developer and as a content writer. Our primary technology was a LAMP sort of stack; that being Linux, Apache, MySql (or MariaDB) and PHP. We were running a version of Magento version 1.7.1, and had some front-end CSS compilers that apparently made front-end development more easier, though I've always thought that the benefits of something like SASS has very marginal benefits over straight CSS. That aside, in each new role I undertook from there, I learnt a lot. So what sort of advice would I give now to junior developers? Or someone inspiring to change career to become a developer?

The first thing I'd say is that there is never a bad time to learn something new. Although not everyone is suited for a role as a software developer, like not everyone can be a Nurse, nor a Doctor, if you have a logical mind and you are able to break down problems to small manageable chunks, and you don't mind learning how to debug then this could be for you.

But as a developer, what issues might you come across? I've found that being a developer is often quite different than programming alone. As a developer, you usually need to work collaboratively, and conform to certain standards and expectations. And whilst you should be given some slack as a junior, your work will still need to be maintainable and scale as necessary.

In my first job proper, the so-called senior developer made two critical mistakes that were even apparent to me after just over one year in the industry; firstly, the version of Magento that we were using was core hacked, meaning that we couldn't easily upgrade it.

My senior colleague developed a service that would produce JSON for pricing data; this data could move up and down every second based on current market prices. Whilst his service was perfectly good, and served the website well, I had developed an iPhone and Android application that was dependent on it.

Shortly after this application was released, he decided to change the API to deliver a different JSON structure. That would have been fine in other circumstances, but he made these changes without consulting anyone else, and whilst he was able to fix the website JavaScript charts that consumed it, he didn't inform me of the changes and therefore my application had been rendered useless. This happened during the last few weeks of my time there, and I had no way to update the application quickly or easily, and he didn't understand the application to fix it as some of it was Objective C and he refused to work outside of his conform zone which rapidly became the PHP framework Laravel.

As a developer, no matter how senior you think you are, or you become, do not make unilateral changes by yourself. Consult others first, especially those people in your team. And if you make a mistake, admit it. The sooner you do, the sooner it can be fixed. Other developers making unilateral changes has caught me out on other occasions too. One server change cost me well over 1 week of debugging because this change wasn't announced to anyone. This change was unnecessary and on a development server, although making such a change without agreement on a production server might have caused even more headaches!

My final piece of advice is to never assume that you know everything, and do not assume that just because you know something that everyone else in your team has that same knowledge. I've done presentations that I never expected to; one was why computers do not divide by zero, and another was about the difference between scalar values and objects. I have a small advantage over many of my younger colleagues in that I grew up programming, and many of the computer magazines that I'd buy growing up would be aimed at teaching children like myself computer programming too. So concepts like Integers and Boolean values, loops, branches and conditionals are kind of second nature to me even if the terminology may have changed. But even good people with good degrees may not have such a good grounding in programming principles even if they're perfectly good developers otherwise.

I've learnt a lot from my colleagues over the years too. As one of my lecturers once said to me, if you're not learning as a developer, you'll soon be obsolete.

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.

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.

Wednesday, 21 December 2011

C start.

Over the past week, I've been spending time making a start on building a 3D game engine for the Sony PSP. Most of this time was spent playing around with the package Blender and then exporting to a format that another 3D thingy can read, I think it was Maya. Then I needed to convert the graphical instance, or object, or whatever into a GMO format.

Once I got this done with all of the textures and stuff (and realising that I really really couldn't be a 3D artist), I started working on the actual engine. It's no where near complete (see the version number, still very alpha), but it's a start - available here: http://pastebin.com/Lrsi0wuS.

Anyway, I realised how much I like C, so that's good. Not quite as much as assembly programming, but close enough. There's a lot to do, so I need to get on with it.

Close up on the PSP

Monday, 12 December 2011

Applet paint package.

I'm not sure why, but I'm unable to post some code here, which I did on my Foundation Degree in Enterprise Computing (MMU), as Blogger thinks my conditions are HTML tags... so anyway, I did this bit of Java to learn about using back buffers and for no other reason, and the link to the code is here:

http://pastebin.com/gH8aW926

Take a look, and post your comments here. Note: some of the code might be depreciated now, but I'm sure you're clever enough to work it out.