====== 8. Memory mapped I/O, PCI bus ====== * for lecturer: [[..:..:..:internal:tutorials:08:start|tutorial 8]] ==== 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 [[https://github.com/cvut/qtrvsim?tab=readme-ov-file#peripherals|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 #include #include #include #include #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 #include #include #include #include #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< 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 #include #include #include #include #include //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 #include #include #include #include #include #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; iwidth) { 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; iheight; i++) { font_bits_t val = *ptr; for (j=0; j0)) { 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 ==== - Bus vs. Point-to-point - What do they have in common and in what are they different? - Show example of point-to-point. - Show example of bus. - I/O device - Describe basic block for generic I/O device on a bus? (hint: there are several devices on a bus, duplex communication). - Describe briefly difference between input and output gate? - Addressing - Explain individual and group addressing. - Explain two-layered addressing, why should I use it? Can you give example of two-layered addressing? - What is the relocation of the bus device? - 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: {{..:..:..:tutorials:ad.png?80|}} Simple I/O device: {{..:..:..:tutorials:isa.png?80|}} - 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. - Discuss address mirroring of our device. == Possible complete solution == {{..:..:..:tutorials:aa_sio3.png?160|}} {{..:..:..:tutorials:aa_sio3t.png?120|}} - Is this device relocable? - Which address should I use to access the device? - Is there an address space mirroring? === PCI Bus === - With help of ''lspci'' utility display PCI devices in your computer. - Find details about PCI devices, addresses in memory and I/O space, they use. - 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: {{..:..:..:tutorials:pci-cfg.png?32|}}) ===== Links ===== * http://en.wikipedia.org/wiki/PCI_configuration_space - Configuration space of a PCI device * http://linuxcommand.org/man_pages/lspci8.html - man pages for ''lspci'' utility * http://www.pcidatabase.com - PCI Vendor and Device Lists