Previous Next Table of Contents

4. Adding code that simulates your hardware

The 68xx family use memory mapped IO. For chips containing builtin IO ports, the memory is divided into two areas:

To add code simulating hardware connected to on-chip IO ports, proceed as described in subchapter "Simulator API for installing an IO port function".

To add code simulating hardware connected to memory outside the internal register area, proceed as in subchapter "Simulator API for memory access".

4.1 Simulator API for installing an IO port function

The simulator has space to store a pointer to a function for each address in the internal register area.

Put the installation code in the routine board_install(). This routine is called when the simulator starts up.

To install an IO simulating function, use the macro

See the example section for details.

4.2 Simulator API for storage of IO port data

The simulator has a memory area called iram[] where IO port data can be stored. Functions installed with ireg_install() can use this area for storage of data, but it is not required.

The simulator will access on-chip IO through the following macros:

To store IO port data, use the ireg_put() routines. To retrieve IO port data, use the ireg_get() routines. See the example section for details.

4.3 Simulator API for memory access

The simulator acesses all memory through the following routines:

These routines were moved to reside in a header file (inc/arch/m68xx/memory.h), to make inlining possible.

To simulate IO outside the internal register are, modify the file inc/arch/m68xx/memory.h to suit your needs.

4.4 Example

The following simple example will show an example with polled IO, and is extended to use interrupt IO.

To be portable to many environments, only the standard C iostream input/output routines are used for user interaction.

A windowing environment could instead have drawn a LED and a switch, and let the user toggle the LED when the switch was pushed with the mouse.

Hardware circuit

Assume a LED is conned to an output port, and a switch is connected to an input port as shown below.

        --------+       LED
             PA7|-----|>---------o +5V
                |        ____ R
        CPU     |    +--|____|---o +5V
                |    |
             PA6|----+
             ___|    |   ___ SW
             IRQ|----+---o o-----o 0V
        --------+

When the user pushes the switch SW, the LED is to toggle. The switch input is pulled down to 0V when the switch is pushed, and the input is also connected to the interrupt input IRQ, to trig an interrupt.

Polled IO

When polled IO is used, the interrupt line is not used.

Target CPU (68xx) code

The following code is to be compiled with a compiler targeted for a CPU in the 68xx series.

char sw_curr; /* Current value of switch SW */
char sw_last; /* Last value of switch SW */

main ()
{
        while (1) {
                sw_curr = _porta & 0x40; /* read PA6 - switch */
                if (sw_curr != sw_last) {
                        _porta ~= 0x80; /* write PA7 - LED */
                }
                sw_last = sw_curr;
        }
}

Simulator code

The following code is to be compiled with a compiler targeted for a the host on which the simulator runs.

Write the following routines (src/boards/examp1.c).

/*
 * Called when CPU reads from PORTA
 */
examp1_porta_getb (offs)
{
        pa6 = ireg_getb (offs) & 0x40;
        if (pa6) {
                printf ("Input is ON\n");
        } else {
                printf ("Input is OFF\n");
        }
        return ireg_getb (offs);
}

/*
 * Called when CPU writes to PORTA
 */
examp1_porta_putb (offs, val)
{
        pa7 = ireg_getb (offs) & 0x80;
        if (pa7) {
                printf ("LED is ON\n");
        } else {
                printf ("LED is OFF\n");
        }
        ireg_putb (offs);
}

/*
 * Called when user enters an unknown command or help from simulator prompt
 *
 *    Input             Return
 *      "h"               1
 *      "e" "sw" "on"     1
 *      "e" "sw" "off"    1
 *      other input       0
 */
int
examp1_cmd (argc, argv)
        int   argc;
        char *argv[];
{
        if (argc < 1)
                return 0;
        /*
         * If user typed 'h', supply some help and return
         */
        if (strncmp (argv[0], "h", strlen("h")) == 0) {
                printf ("EXAMP1 commands:\n");
                printf ("       e  sw [on|off] - set switch SW on or off\n");
                return 1;
        }
        /*
         * Strip command prefix
         */
        if (strcmp (argv[0], "e") != 0) {
                return 0;
        }
        argv++;
        argc--;
        if (strcmp (argv[0], "sw") == 0) {
                if (argc > 1) {
                        if (strcmp (argv[1], "on") == 0) {
                                sw = ON;
                        } else if (strcmp (argv[1], "off") == 0) {
                                sw = OFF;
                        } else {
                                printf ("sw can be 'on' or 'off' only\n");
                                return 0;
                        }
                }
                switch(sw) {
                case ON:
                        ireg_putb(PORTA, ireg_getb(PORTA) | 0x40);
                        return 1;
                case OFF:
                        ireg_putb(PORTA, ireg_getb(PORTA) & ~0x40);
                        return 1;
                }
        }
}

/*
 * board_install - install user functions
 *
 * Called when the simulator is starting.
 */
board_install ()
{
        command_install (examp1_cmd);
        ireg_install (PORTA, examp1_porta_getb, examp1_porta_putb);
}

Add the new target examp1 to the Makefile in the src/boards/ directory and compile.

Interrupt IO

NB! The simulator has currently no way to install user defined functions for interrupt lines similar to that for internal registers.

Target CPU (68xx) code

char sw_curr; /* Current value of switch SW */
char sw_last; /* Last value of switch SW */

/*
 * IRQ Interrupt handler
 *
 * Add required code to install the routine _irq() as an interrupt
 * handler here. Some compilers use #pragma interrupt@IRQADDRESS
 */
_irq ()
{
        sw_curr = _porta & 0x40; /* read PA6 - switch */
}

main ()
{
        while (1) {
                if (sw_curr != sw_last) {
                        _porta ~= 0x80;  /* write PA7 - LED */
                }
                sw_last = sw_curr;
        }
}

Simulator code

NB. This subchapter is incomplete! Missing: How to change the value of the IRQ line. The simulator currently has no defined way to do this.

In addition to Polled IO, add the following.

irq_int ()
{
}

instr_exec ()
{
        :
        if (irq_int ()) {
                /* IRQ interrupt occured */
        }
        :
}


Previous Next Table of Contents