Cogs and Levers A blog full of technical stuff

Mode X.. plus some!

So, not much of tutorial here - just a neat layout of setup code for a few mode X modes I’ve come across now and then.

First of all, just some formalities. Setting Mode X tweaks to the VGA is a massive port-out exercise. Creating the following macro cut down on my code heaps.

outp MACRO port, value
	mov dx, port
	mov al, value
	out dx, al
ENDM

So you can see, it just gives sending a byte out to a port a bit of syntactical sugar in assembly language. Easy.

The only other piece of formality is, you must have set the video display into MCGA (mode 13) first:

set_mcga:
    mov ax, 0013h
    int 10h
	
    ret

On to the modes.

tweak_160x120:
    ; --------------------------
    ; 160x120
    ;
    ; pages = 13
    ; line size = 40
    ; page size = 19200
    ; --------------------------
	
    outp 03d4h, 011h
	
    mov dx, 03d5h
    in  al, dx
    and al, 07fh
    mov bl, al
	
    outp 03d4h, 011h
    outp 03d5h, bl
    outp 03c2h, 0e3h
    outp 03d4h, 000h
    outp 03d5h, 032h
    outp 03d4h, 001h
    outp 03d5h, 027h
    outp 03d4h, 002h
    outp 03d5h, 028h
    outp 03d4h, 003h
    outp 03d5h, 020h
    outp 03d4h, 004h
    outp 03d5h, 02bh                  
    outp 03d4h, 005h
    outp 03d5h, 070h                  
    outp 03d4h, 006h
    outp 03d5h, 00dh                  
    outp 03d4h, 007h
    outp 03d5h, 03eh                  
    outp 03d4h, 008h
    outp 03d5h, 000h                 
    outp 03d4h, 009h
    outp 03d5h, 043h                 
    outp 03d4h, 010h
    outp 03d5h, 0eah                  
    outp 03d4h, 011h
    outp 03d5h, 0ach                 
    outp 03d4h, 012h
    outp 03d5h, 0dfh                  
    outp 03d4h, 013h
    outp 03d5h, 014h                  
    outp 03d4h, 014h
    outp 03d5h, 000h                  
    outp 03d4h, 015h
    outp 03d5h, 0e7h                 
    outp 03d4h, 016h
    outp 03d5h, 006h                  
    outp 03d4h, 017h
    outp 03d5h, 0e3h                  
    outp 03c4h, 001h
    outp 03c5h, 001h                  
    outp 03c4h, 003h
    outp 03c5h, 000h                  
    outp 03c4h, 004h
    outp 03c5h, 006h                 
    outp 03ceh, 005h
    outp 03cfh, 040h                
    outp 03ceh, 006h
    outp 03cfh, 005h

    mov dx, 03dah
    in  al, dx

    outp 03c0h, 010h or 020h
    outp 03c0h, 041h

    mov dx, 03dah
    in  al, dx

    outp 03c0h, 011h or 020h
    outp 03c0h, 0

    mov dx, 03dah
    in  al, dx

    outp 03c0h, 012h or 020h
    outp 03c0h, 0fh

    mov dx, 03dah
    in  al, dx

    outp 03c0h, 013h or 020h
    outp 03c0h, 0

    mov dx, 03dah
    in  al, dx

    outp 03c0h, 014h or 020h
    outp 03c0h, 0

    outp 03d4h, 011h
    
    mov dx, 03d5h
    in  al, dx
    and al, 80h
    mov bl, al

    outp 03d4h, 011h
    outp 03d5h, bl

    ret

tweak_296x220:
    ; --------------------------
    ; 296x220
    ;
    ; pages = 4
    ; line size = 74
    ; page size = 65120
    ; --------------------------

    outp 03d4h, 011h

    mov dx, 03d5h
    in  al, dx
    and al, 7fh
    mov bl, al
	
    outp 03d4h, 011h
    outp 03d5h, bl

    outp 03c2h, 0e3h
    outp 03d4h, 000h
    outp 03d5h, 05fh
    outp 03d4h, 001h
    outp 03d5h, 049h
    outp 03d4h, 002h
    outp 03d5h, 050h
    outp 03d4h, 003h
    outp 03d5h, 082h
    outp 03d4h, 004h
    outp 03d5h, 053h
    outp 03d4h, 005h
    outp 03d5h, 080h
    outp 03d4h, 006h
    outp 03d5h, 00dh
    outp 03d4h, 007h
    outp 03d5h, 03eh
    outp 03d4h, 008h
    outp 03d5h, 000h
    outp 03d4h, 009h
    outp 03d5h, 041h
    outp 03d4h, 010h
    outp 03d5h, 0d7h
    outp 03d4h, 011h
    outp 03d5h, 0ach
    outp 03d4h, 012h
    outp 03d5h, 0b7h
    outp 03d4h, 013h
    outp 03d5h, 025h
    outp 03d4h, 014h
    outp 03d5h, 000h
    outp 03d4h, 015h
    outp 03d5h, 0e7h
    outp 03d4h, 016h
    outp 03d5h, 006h
    outp 03d4h, 017h
    outp 03d5h, 0e3h
    outp 03c4h, 001h
    outp 03c5h, 001h
    outp 03c4h, 004h
    outp 03c5h, 006h
    outp 03ceh, 005h
    outp 03cfh, 040h
    outp 03ceh, 006h
    outp 03cfh, 005h

    mov dx, 03dah
    in  al, dx

    outp 03c0h, 010h or 020h
    outp 03c0h, 041h

    mov dx, 03dah
    in  al, dx
	
    outp 03c0h, 013h or 020h
    outp 03c0h, 0

    outp 03d4h, 011h

    mov dx, 03d5h
    in  al, dx
    and al, 80h
    mov bl, al
	
    outp 03d4h, 011h
    outp 03d5h, bl

    ret

tweak_320x200:
    ; --------------------------
    ; 320x200
    ;
    ; pages = 4
    ; line size = 80
    ; page size = 64000
    ; --------------------------

    outp 03c4h, 04h
    outp 03c5h, 06h

    outp 03d4h, 017h
    outp 03d5h, 0E3h

    outp 03d4h, 014h
    outp 03d5h, 0
	
    ret

tweak_320x240:
    ; --------------------------
    ; 320x240
    ;
    ; pages = 3
    ; line size = 80
    ; page size = 76800
    ; --------------------------

    outp 03d4h, 11h

    mov dx, 03d5h
    in  al, dx
    and al, 7fh
    mov bl, al

    outp 03d4h, 11h
    outp 03d5h, bl

    outp 03c2h, 0e3h
    outp 03d4h, 000h
    outp 03d5h, 05fh
    outp 03d4h, 001h
    outp 03d5h, 04fh
    outp 03d4h, 002h
    outp 03d5h, 050h
    outp 03d4h, 003h
    outp 03d5h, 082h
    outp 03d4h, 004h
    outp 03d5h, 054h
    outp 03d4h, 005h
    outp 03d5h, 080h
    outp 03d4h, 006h
    outp 03d5h, 00dh
    outp 03d4h, 007h
    outp 03d5h, 03eh
    outp 03d4h, 008h
    outp 03d5h, 000h
    outp 03d4h, 009h
    outp 03d5h, 041h
    outp 03d4h, 010h
    outp 03d5h, 0eah
    outp 03d4h, 011h
    outp 03d5h, 0ach
    outp 03d4h, 012h
    outp 03d5h, 0dfh
    outp 03d4h, 013h
    outp 03d5h, 028h
    outp 03d4h, 014h
    outp 03d5h, 000h
    outp 03d4h, 015h
    outp 03d5h, 0e7h
    outp 03d4h, 016h
    outp 03d5h, 006h
    outp 03d4h, 017h
    outp 03d5h, 0e3h
    outp 03c4h, 001h
    outp 03c5h, 001h
    outp 03c4h, 004h
    outp 03c5h, 006h
    outp 03ceh, 005h
    outp 03cfh, 040h
    outp 03ceh, 006h
    outp 03cfh, 005h

    mov dx, 03dah
    in  al, dx
	
    outp 03c0h, 010h or 020h
    outp 03c0h, 041h

    mov dx, 03dah
    in  al, dx
	
    outp 03c0h, 013h or 020h
    outp 03c0h, 0

    outp 03d4h, 011h

    mov dx, 03d5h
    in  al, dx
    or  al, 80h
    mov bl, al

    outp 03d4h, 11h
    outp 03d5h, bl

    ret

tweak_320x400:
    ; --------------------------
    ; 320x400
    ;
    ; pages = 2
    ; line size = 80
    ; page size = 128000
    ; --------------------------

    outp 03c4h, 004h
    outp 03c5h, 006h
    outp 03d4h, 017h
    outp 03d5h, 0E3h
    outp 03d4h, 014h
    outp 03d5h, 000h
    outp 03d4h, 009h
    outp 03d5h, 040h

    ret

tweak_360x360:
    ; --------------------------
    ; 360x360
    ;
    ; pages = 2
    ; line size = 90
    ; page size = 129600
    ; --------------------------

    outp 03d4h, 011h

    mov dx, 03d5h
    in  al, dx
    and al, 7fh
    mov bl, al

    outp 03d4h, 011h
    outp 03d5h, bl

    outp 03c2h, 067h
    outp 03d4h, 000h
    outp 03d5h, 06bh
    outp 03d4h, 001h
    outp 03d5h, 059h
    outp 03d4h, 002h
    outp 03d5h, 05ah
    outp 03d4h, 003h
    outp 03d5h, 08eh
    outp 03d4h, 004h
    outp 03d5h, 05eh
    outp 03d4h, 005h
    outp 03d5h, 08ah
    outp 03d4h, 006h
    outp 03d5h, 0bfh
    outp 03d4h, 007h
    outp 03d5h, 01fh
    outp 03d4h, 008h
    outp 03d5h, 000h
    outp 03d4h, 009h
    outp 03d5h, 040h
    outp 03d4h, 010h
    outp 03d5h, 088h
    outp 03d4h, 011h
    outp 03d5h, 085h
    outp 03d4h, 012h
    outp 03d5h, 067h
    outp 03d4h, 013h
    outp 03d5h, 02dh
    outp 03d4h, 014h
    outp 03d5h, 000h
    outp 03d4h, 015h
    outp 03d5h, 06dh
    outp 03d4h, 016h
    outp 03d5h, 0bah
    outp 03d4h, 017h
    outp 03d5h, 0e3h
    outp 03c4h, 001h
    outp 03c5h, 001h
    outp 03c4h, 004h
    outp 03c5h, 006h
    outp 03ceh, 005h
    outp 03cfh, 040h
    outp 03ceh, 006h
    outp 03cfh, 005h

    mov dx, 03dah
    in  al, dx
	
    outp 03c0h, 010h or 020h
    outp 03c0h, 041h

    mov dx, 03dah
    in  al, dx

    outp 03c0h, 013h or 020h
    outp 03c0h, 0

    outp 03d4h, 011h

    mov dx, 03d5h
    in  al, dx
    or  al, 80h
    mov bl, al
	
    outp 03d4h, 011h
    outp 03d5h, bl	

    ret

tweak_400x300:
    ; --------------------------
    ; 400x300
    ;
    ; pages = 2
    ; line size = 100
    ; page size = 120000
    ; --------------------------
	
    outp 03d4h, 011h

    mov dx, 03d5h
    in  al, dx
    and al, 7fh
    mov bl, al

    outp 03d4h, 011h
    outp 03d5h, bl	

    outp 03c2h, 0e7h                    
    outp 03d4h, 000h 
    outp 03d5h, 071h                    
    outp 03d4h, 001h 
    outp 03d5h, 063h                    
    outp 03d4h, 002h 
    outp 03d5h, 064h                    
    outp 03d4h, 003h 
    outp 03d5h, 092h                    
    outp 03d4h, 004h 
    outp 03d5h, 067h                   
    outp 03d4h, 005h 
    outp 03d5h, 082h                    
    outp 03d4h, 006h 
    outp 03d5h, 046h                    
    outp 03d4h, 007h 
    outp 03d5h, 01fh                    
    outp 03d4h, 008h 
    outp 03d5h, 000h                    
    outp 03d4h, 009h 
    outp 03d5h, 040h                    
    outp 03d4h, 010h 
    outp 03d5h, 031h                    
    outp 03d4h, 011h 
    outp 03d5h, 080h                     
    outp 03d4h, 012h 
    outp 03d5h, 02bh                    
    outp 03d4h, 013h 
    outp 03d5h, 032h                    
    outp 03d4h, 014h 
    outp 03d5h, 000h                    
    outp 03d4h, 015h 
    outp 03d5h, 02fh                    
    outp 03d4h, 016h 
    outp 03d5h, 044h                    
    outp 03d4h, 017h 
    outp 03d5h, 0e3h                    
    outp 03c4h, 001h 
    outp 03c5h, 001h                    
    outp 03c4h, 002h 
    outp 03c5h, 00fh                    
    outp 03c4h, 004h 
    outp 03c5h, 006h                    
    outp 03ceh, 005h 
    outp 03cfh, 040h                    
    outp 03ceh, 006h 
    outp 03cfh, 005h 
                       
    mov dx, 03dah
    in  al, dx
	
    outp 03c0h, 010h or 020h
    outp 03c0h, 041h
    
    mov dx, 03dah
    in  al, dx

    outp 03c0h, 013h or 020h
    outp 03c0h, 0
    
    outp 03d4h, 011h
	
    mov dx, 03d5h
    in  al, dx
    or  al, 80h
    mov bl, al	
	
    outp 03d4h, 011h
    outp 03d5h, bl

    ret

I will have an update to this post. There are some nuances that I’d much prefer explain to you with a couple of nice code blocks rather than how I’m just going to throw it into the page.

These chunks will be helpful in page selection and optimizing page draws to multiple pages at once.

; setting a page
; activeOffset = vgapage + (page * pageSize / 4);
; enable all planes
; outp 03c4h, 02h
; outp 03c5h, 0fh

Some really good references on this topic are

Well, that’s it for now.

Offscreen Mesa3D

As a quick bookmark, this part of the Mesa3D project: Off-screen Rendering.

Looks like it might be a viable option for some of the lower-end hardware I’ve come across lately.

Music, Calculators & Big Snakes

Introduction

I play a lot of music. I mean a lot of music. Guitar, Bass, Piano, Drums, Harp – what ever I can get my hands on, I’ll give it a go. So, the neurons in charge of keeping my technical side in check may have made their way into the creative side of my brain.

The net result was me creating a project that mashes mathematics, data analysis and music theory into a few classed called musica.

So what?

Yeah, basically.. But, I am who I am - so it’ more of a matter of “why not?”.

I’d previously tried building a Ruby on Rails application to give me graphical representations of musically related elements on screen. A scale is a pattern of intervals realised once a root note is put in place. This scale can then be harmonised at every step of the scale by employing every second note from the specific step. How complex these harmonised chords are will depend on how many steps you include in the chords that you build.

The most interesting part of this library, I think, is its distinct lack of database. It has made the code quite verbose in parts but I intend to fix this, even if it does mean employing an intermediary database at a later stage.

What can it do?

The major, harmonic & melodic minor scales (and all of their modes) are statically provisioned. You can use these in code to perform operations like voicing a scale when used in conjunction with a Note object.

Immediately, we can get information about notes:

>>> Notes.by_distance(0)
<musica.notes.Note object at 0x10f961090>
>>> Notes.by_distance(0).__unicode__()
'c'

Information about scales:

>>> Scales.scales[0]
<musica.scales.Scale object at 0x10f963090>
>>> Scales.scales[0].name
'Ionian'
>>> Scales.scales[0].intervals
[<musica.intervals.Interval object at 0x10f961950>, <musica.intervals.Interval object at 0x10f9619d0>, <musica.intervals.Interval object at 0x10f961a50>, <musica.intervals.Interval object at 0x10f961a90>, <musica.intervals.Interval object at 0x10f961b10>, <musica.intervals.Interval object at 0x10f961b90>, <musica.intervals.Interval object at 0x10f961c10>]

Voicing a scale (in this instance voicing Ionian (major) over C)

>>> steps = Scales.scales[0].voice(Notes.by_distance(0))
>>> for s in steps:
...     print 'note: ' + s['note'].__unicode__() + ', interval: ' + s['interval'].short_name
... 
note: c, interval: PU
note: d, interval: M2
note: e, interval: M3
note: f, interval: P4
note: g, interval: P5
note: a, interval: M6
note: b, interval: M7

Still so much to do …

Still, we need to get chords harmonising from these voiced scales. These are just patterns after all. An intelligent chord builder would also be of value I think. Something where we don’t have to explicitly map out chord names to interval sets statically. Just knowing that a root, major third and perfect fifth are a major chord.

That’d be a cool calculator, I think.

Calling Assembly from C (64 bit)

In a previous post, I spoke about calling assembly language routines from C in 32-bit land. In this post, I aim to show you the same technique only this time using a 64 bit architecture.

I’ll be using the same technology stack as last time with NASM as my assembler and GCC as my C compiler. The code snippets that you’ll see in this post have been compiled and linked together on the linux platform.

Alright then. On with the code!

The C-code is not different from the 32-bit version as mentioned in my previous post. Now that’s portability for you!

#include <stdio.h>

/** Forward declaration for our add function */
int add(int, int);

int main() {

   /* add some numbers */
   int x = add(5, 4);

   /* print the result out */
   printf("5+4=%d\n", x);

   return 0;
}

The assembly language module has changed somewhat though.

global add

section .text

add:
   mov   rax, rdi    ; get the first parameter
   add   rax, rsi    ; add the second parameter
                     ; leaving the return value in rax
   ret

Immediately you can see that a new set of registers are being used and the stack is no longer being used to take parameters in from external calls.

The change in calling convention can be studied in further detail here, however it’s just important to mention this:

Once arguments are classified, the registers get assigned (in left-to-right order) for passing as follows: If the class is MEMORY, pass the argument on the stack. If the class is INTEGER, the next available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9 is used

So, the first argument is passed in RDI and the second in RSI. The return value remains the same being passed back to the caller using the accumulator register (RAX in 64-bit land). There are many resources to read up on when it comes to the 64 bit architecture; Intel and Wikipedia are both excellent resources.

Finally, when it comes to building these files together, it’s (again) very similar to its 32bit counterpart.

$ gcc -c add.c -o add.o
$ nasm -f elf64 maths.asm -o maths.o
$ gcc -m64 add.o maths.o -o add

We’re done!

Unix Networking: Server

The following snippet is a bare-bones server.

int sockfd, new_fd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr;
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;

/* fill out the address structure */
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

/* get the address information */
getaddrinfo(NULL, PORT, &hints, &servinfo);

/* open the socket */
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

/* allow the socket to be re-used */
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

/* bind the socket to the address */
bind(sockfd, p->ai_addr, p->ai_addrlen);

/* free up the address structure */
freeaddrinfo(servinfo);

/* start the socket listening */
listen(sockfd, BACKLOG);

/* accept the first connect */
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);

/* send the client some data */
send(new_fd, "Hello, world!", 13, 0);

/* finished with the client & server */
close(new_fd);
close(sockfd);

Further reading The getaddrinfo system call The socket system call The bind system call The listen system call The accept system call The recv system call The send system call