8. Memory mapped I/O, PCI bus

QtRvSim

Program for working with knobs QtRvSim

#base of SPILED port region
.equ SPILED_REG_BASE,       0xffffc100

#RGB LED 1 
.equ SPILED_REG_LED_RGB1,   0xffffc110
.equ SPILED_REG_LED_RGB1_o,   0x0010

#RGB LED 2 
.equ SPILED_REG_LED_RGB2,   0xffffc114
.equ SPILED_REG_LED_RGB2_o,   0x0014

#Three 8 bit Knobs
#the highest byte used for knobs press 
.equ SPILED_REG_KNOBS_8BIT, 0xffffc124 
.equ SPILED_REG_KNOBS_8BIT_o, 0x0024

#32 LED line
.equ SPILED_REG_LED_LINE,   0xffffc104
.equ SPILED_REG_LED_LINE_o,   0x0004

    li   a0, SPILED_REG_BASE # a0 points to I/O memory area
    ori  t2, t2, -1
loop:
    lw   t0, SPILED_REG_KNOBS_8BIT_o(a0)   # read data from knobs
    sw   t0, SPILED_REG_LED_RGB1_o(a0)
    xor  t1, t0, t2
    sw   t1, SPILED_REG_LED_RGB2_o(a0)
    srli t0, t0, 24
    andi t0, t0, 4
    beq  t0, zero, loop       # is red knob pressed

    ebreak                    # end program

Serial terminal writing Peripherals:

  li t0, 0xffffc000   // base address into memory mapped I/O area
  addi t1, zero, 48
  addi t6, zero, 1234
  addi t2, zero, 10
loop:
  lw   t3, 0x08(t0)
  andi t3, t3, 1
  beq  t3, zero, loop  
  sw   t1, 0x0c(t0)
  addi t1, t1, 1
  addi t2, t2, -1
  bne  t2, zero, loop
  ebreak

Serial line echoing:

  li t0, 0xffffc000   // base address into memory mapped I/O area
  addi t1, zero, 48
  addi t6, zero, 1234
  addi t2, zero, 10
loop_rx:
  lw   t3, 0x0(t0)
  andi t3, t3, 1
  beq  t3, zero, loop_rx
  lw   t1, 4(t0)  
loop_tx:
  lw   t3, 0x08(t0)
  andi t3, t3, 1
  beq  t3, zero, loop_tx  
  sw   t1, 0x0c(t0)
  addi t1, t1, 1
  addi t2, t2, -1
  bne  t2, zero, loop_rx
  ebreak

LED line:

  lui t0, 0xffffc
  ori t0, t0, 0x100

  addi t1, zero, 5
loop:
  sw t1, 4(t0)
  slli t1, t1, 1
  bne t1, zero, loop
  ebreak

MZApo

LED line

#define _POSIX_C_SOURCE 200112L

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>

#include "mzapo_parlcd.h"
#include "mzapo_phys.h"
#include "mzapo_regs.h"

int main(int argc, char *argv[]) {
  unsigned char *mem_base;
  uint32_t val_line=5;
  int i;
  printf("Hello world\n");

  sleep(1);

  /*
   * Setup memory mapping which provides access to the peripheral
   * registers region of RGB LEDs, knobs and line of yellow LEDs.
   */
  mem_base = map_phys_address(SPILED_REG_BASE_PHYS, SPILED_REG_SIZE, 0);

  /* If mapping fails exit with error code */
  if (mem_base == NULL)
    exit(1);

  for (i=0; i<30; i++) {
     *(volatile uint32_t*)(mem_base + SPILED_REG_LED_LINE_o) = val_line;
     val_line<<=1;
     printf("LED val 0x%x\n", val_line);
     sleep(1);
  }

  printf("Goodbye world\n");

  return 0;
}

Knobs and led line

/*******************************************************************
  Project main function template for MicroZed based MZ_APO board
  designed by Petr Porazil at PiKRON
 
  change_me.c      - main file
 
  include your name there and license for distribution.
 
  Remove next text: This line should not appear in submitted
  work and project name should be change to match real application.
  If this text is there I want 10 points subtracted from final
  evaluation.
 
 *******************************************************************/
 
#define _POSIX_C_SOURCE 200112L
 
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
 
#include "mzapo_parlcd.h"
#include "mzapo_phys.h"
#include "mzapo_regs.h"
#include "serialize_lock.h"
 
int main(int argc, char *argv[]) {
  unsigned char *mem_base;
  uint32_t val_line=0x5;
  int i;
  struct timespec loop_delay;
  loop_delay.tv_sec = 0;
  loop_delay.tv_nsec = 50 * 1000 * 1000;
 
  printf("Hello world\n");
 
  sleep(1);
 
  /*
   * Setup memory mapping which provides access to the peripheral
   * registers region of RGB LEDs, knobs and line of yellow LEDs.
   */
  mem_base = map_phys_address(SPILED_REG_BASE_PHYS, SPILED_REG_SIZE, 0);
 
  /* If mapping fails exit with error code */
  if (mem_base == NULL)
    exit(1);
 
  while (1) {
     uint32_t knobs = *(volatile uint32_t*)
       (mem_base + SPILED_REG_KNOBS_8BIT_o);
     int blue_knob = (knobs & 0xff);
     int pos_pat = (blue_knob * 29)/255;  
     val_line = 5<<pos_pat;
 
     *(volatile uint32_t*)(mem_base + SPILED_REG_LED_LINE_o) = val_line;
     printf("LED val 0x%x\n", val_line);
     clock_nanosleep(CLOCK_MONOTONIC, 0, &loop_delay, NULL);
  }
 
  printf("Goodbye world\n");
 
  return 0;
}

LCD example moving_square.c:

/*******************************************************************
  Project main function template for MicroZed based MZ_APO board
  designed by Petr Porazil at PiKRON
 
  include your name there and license for distribution.
 
  Remove next text: This line should not appear in submitted
  work and project name should be change to match real application.
  If this text is there I want 10 points subtracted from final
  evaluation.
 
 *******************************************************************/
 
#define _POSIX_C_SOURCE 200112L
 
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <termios.h>            //termios, TCSANOW, ECHO, ICANON
 
#include "mzapo_parlcd.h"
#include "mzapo_phys.h"
#include "mzapo_regs.h"
 
unsigned short *fb;
 
void draw_pixel(int x, int y, unsigned short color) {
  if (x>=0 && x<480 && y>=0 && y<320) {
    fb[x+480*y] = color;
  }
}
 
 
int main(int argc, char *argv[]) {
  unsigned char *parlcd_mem_base, *mem_base;
  int i,j;
  int ptr;
  unsigned int c;
  fb  = (unsigned short *)malloc(320*480*2);
 
  printf("Hello world\n");
 
  parlcd_mem_base = map_phys_address(PARLCD_REG_BASE_PHYS, PARLCD_REG_SIZE, 0);
  if (parlcd_mem_base == NULL)
    exit(1);
 
  mem_base = map_phys_address(SPILED_REG_BASE_PHYS, SPILED_REG_SIZE, 0);
  if (mem_base == NULL)
    exit(1);
 
  parlcd_hx8357_init(parlcd_mem_base);
 
  parlcd_write_cmd(parlcd_mem_base, 0x2c);
  ptr=0;
  for (i = 0; i < 320 ; i++) {
    for (j = 0; j < 480 ; j++) {
      c = 0;
      fb[ptr]=c;
      parlcd_write_data(parlcd_mem_base, fb[ptr++]);
    }
  }
 
  struct timespec loop_delay;
  loop_delay.tv_sec = 0;
  loop_delay.tv_nsec = 150 * 1000 * 1000;
  int xx=0, yy=0;
  while (1) {
 
    int r = *(volatile uint32_t*)(mem_base + SPILED_REG_KNOBS_8BIT_o);
    if ((r&0x7000000)!=0) {
      break;
    }
    xx = ((r&0xff)*480)/256;
    yy = (((r>>8)&0xff)*320)/256;
 
    for (ptr = 0; ptr < 320*480 ; ptr++) {
        fb[ptr]=0u;
    }
    for (j=0; j<60; j++) {
      for (i=0; i<60; i++) {
        draw_pixel(i+xx,j+yy,0x7ff);
      }
    }
 
    parlcd_write_cmd(parlcd_mem_base, 0x2c);
    for (ptr = 0; ptr < 480*320 ; ptr++) {
        parlcd_write_data(parlcd_mem_base, fb[ptr]);
    }
 
    clock_nanosleep(CLOCK_MONOTONIC, 0, &loop_delay, NULL);
  }
 
  parlcd_write_cmd(parlcd_mem_base, 0x2c);
  for (ptr = 0; ptr < 480*320 ; ptr++) {
    parlcd_write_data(parlcd_mem_base, 0);
  }
 
  printf("Goodbye world\n");
 
  return 0;
}

flying_letters.c:

/*******************************************************************
  Project main function template for MicroZed based MZ_APO board
  designed by Petr Porazil at PiKRON
 
  include your name there and license for distribution.
 
  Remove next text: This line should not appear in submitted
  work and project name should be change to match real application.
  If this text is there I want 10 points subtracted from final
  evaluation.
 
 *******************************************************************/
 
#define _POSIX_C_SOURCE 200112L
 
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
 
#include "mzapo_parlcd.h"
#include "mzapo_phys.h"
#include "mzapo_regs.h"
#include "font_types.h"
 
#define M_PI 3.1415
 
unsigned int hsv2rgb_lcd(int hue, int saturation, int value) {
  hue = (hue%360);    
  float f = ((hue%60)/60.0);
  int p = (value*(255-saturation))/255;
  int q = (value*(255-(saturation*f)))/255;
  int t = (value*(255-(saturation*(1.0-f))))/255;
  unsigned int r,g,b;
  if (hue < 60){
    r = value; g = t; b = p;
  } else if (hue < 120) {
    r = q; g = value; b = p;
  } else if (hue < 180) {
    r = p; g = value; b = t;
  } else if (hue < 240) {
    r = p; g = q; b = value;
  } else if (hue < 300) {
    r = t; g = p; b = value;
  } else {
    r = value; g = p; b = q;
  }
  r>>=3;
  g>>=2;
  b>>=3;
  return (((r&0x1f)<<11)|((g&0x3f)<<5)|(b&0x1f));
}
 
unsigned short fb[320*480*2];
font_descriptor_t *fdes;
int scale=4;
 
void draw_pixel(int x, int y, unsigned short color) {
  if (x>=0 && x<480 && y>=0 && y<320) {
    fb[x+480*y] = color;
  }
}
 
void draw_pixel_big(int x, int y, unsigned short color) {
  int i,j;
  for (i=0; i<scale; i++) {
    for (j=0; j<scale; j++) {
      draw_pixel(x+i, y+j, color);
    }
  }
}
 
int char_width(int ch) {
  int width;
  if (!fdes->width) {
    width = fdes->maxwidth;
  } else {
    width = fdes->width[ch-fdes->firstchar];
  }
  return width;
}
 
void draw_char(int x, int y, char ch, unsigned short color) {
  int w = char_width(ch);
  const font_bits_t *ptr;
  if ((ch >= fdes->firstchar) && (ch-fdes->firstchar < fdes->size)) {
    if (fdes->offset) {
      ptr = &fdes->bits[fdes->offset[ch-fdes->firstchar]];
    } else {
      int bw = (fdes->maxwidth+15)/16;
      ptr = &fdes->bits[(ch-fdes->firstchar)*bw*fdes->height];
    }
    int i, j;
    for (i=0; i<fdes->height; i++) {
      font_bits_t val = *ptr;
      for (j=0; j<w; j++) {
        if ((val&0x8000)!=0) {
          draw_pixel_big(x+scale*j, y+scale*i, color);
        }
        val<<=1;
      }
      ptr++;
    }
  }
}
 
 
int main(int argc, char *argv[]) {
  unsigned char *parlcd_mem_base;
  int i,j;
  printf("Hello\n");
  parlcd_mem_base = map_phys_address(PARLCD_REG_BASE_PHYS, PARLCD_REG_SIZE, 0);
  if (parlcd_mem_base == NULL)
    exit(1);
 
  parlcd_hx8357_init(parlcd_mem_base);
 
  parlcd_write_cmd(parlcd_mem_base, 0x2c);
  for (i = 0; i < 320 ; i++) {
    for (j = 0; j < 480 ; j++) {
      parlcd_write_data(
        parlcd_mem_base, hsv2rgb_lcd(j, 255, (i*255)/320));
    }
  }
  sleep(5);
 
  int k;
  int ptr;
  struct timespec loop_delay = 
    {.tv_sec = 0, .tv_nsec = 120 * 1000 * 1000};
 
 
  fdes = &font_winFreeSystem14x16;
 
  float g=1.0;
  for (k=0; k<=80; k+=5) {
    float alfa=((10+k)*M_PI)/180.0;
    float vx=32*(M_PI/2.0-alfa);
    float vy=32*(2.0*alfa/M_PI);
    float x=1;
    float y=1;
    char ch=('a'+k/5);
    printf("Flying:%c\n",ch);
    unsigned int col=hsv2rgb_lcd(4*k,255,255);
    while ((x<480) && (y>0)) {
      for (ptr = 0; ptr < 320*480 ; ptr++) {
        fb[ptr]=0;
      }
      draw_char((int)x,250-(int)y, ch, col);
      x+=vx;
      y+=vy;
      vx = vx*0.97;
      vy = vy*0.97-g;
      parlcd_write_cmd(parlcd_mem_base, 0x2c);
      for (ptr = 0; ptr < 480*320 ; ptr++) {
        parlcd_write_data(parlcd_mem_base, fb[ptr]);
      }
      clock_nanosleep(CLOCK_MONOTONIC, 0, &loop_delay, NULL);
    }
  }
  ptr=0;
  parlcd_write_cmd(parlcd_mem_base, 0x2c);
  for (i = 0; i < 320 ; i++) {
    for (j = 0; j < 480 ; j++) {
      fb[ptr]=0;
      parlcd_write_data(parlcd_mem_base, fb[ptr++]);
    }
  }
 
  printf("Goodbye\n");
 
  return 0;
}

Basic terms

  1. Bus vs. Point-to-point
    1. What do they have in common and in what are they different?
    2. Show example of point-to-point.
    3. Show example of bus.
  2. I/O device
    1. Describe basic block for generic I/O device on a bus? (hint: there are several devices on a bus, duplex communication).
    2. Describe briefly difference between input and output gate?
  3. Addressing
    1. Explain individual and group addressing.
    2. Explain two-layered addressing, why should I use it? Can you give example of two-layered addressing?
    3. What is the relocation of the bus device?
    4. What is a address space mirroring?

Circuit realization for I/O device

Circuit realization of I/O device on PCI and more modern is too complex for the introductory course like ours. For our educational purposes it is more suitable to show you circuit realization of old ISA bus.

Address decoder:

Simple I/O device:

  1. Describe address decoder. Lets have a 16b bus. The device has 64 I/O registers. Task: show how to place a registry field to I/O space, begining at address 0x1480. You can use only one 74LS688 circuit.
  2. Discuss address mirroring of our device.
Possible complete solution

  1. Is this device relocable?
  2. Which address should I use to access the device?
  3. Is there an address space mirroring?

PCI Bus

  1. With help of lspci utility display PCI devices in your computer.
  2. Find details about PCI devices, addresses in memory and I/O space, they use.
  3. Using lspci -xxx display config space of given PCI device and for selected devices find out:
    • type of the device
    • manufacturer
    • memory addresses it uses
    • I/O addresses it uses
Design of PCI device

In lectures you have seen examples of building blocks usable for PCI device, including control finite state automaton. Extend this design to add a configuration read and write. (A diagram for config read and write: )

courses/b35apo/en/tutorials/08/start.txt · Last modified: 2024/04/10 18:13 by stepan