From da77ed14ee19be9f3cf0fabe1eb1efb0085bcf04 Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Mon, 21 Feb 2011 18:05:44 +0000 Subject: [PATCH] board_hd44780: New sample code Emulated a complete HD44780 LCd screen, and uses a standard AVR driver to write on it. Signed-off-by: Michel Pollet --- examples/board_charlcd/ac_input.c | 18 - examples/board_charlcd/ac_input.h | 23 - examples/board_charlcd/atmega48_charlcd.c | 62 - examples/board_charlcd/atmega48_lcd.c | 146 --- examples/board_charlcd/atmega48_lcd.h | 33 - examples/board_charlcd/charlcd.c | 228 ---- examples/board_charlcd/hd44780.c | 185 --- examples/board_charlcd/hd44780.h | 69 -- examples/board_charlcd/hd44780_glut.c | 94 -- examples/board_charlcd/hd44780_glut.h | 10 - .../{board_charlcd => board_hd77480}/Makefile | 29 +- examples/board_hd77480/README | 21 + examples/board_hd77480/atmega48_charlcd.c | 114 ++ examples/board_hd77480/avr_hd44780.c | 216 ++++ examples/board_hd77480/avr_hd44780.h | 105 ++ examples/board_hd77480/avr_hd44780_conf.h | 23 + examples/board_hd77480/charlcd.c | 246 ++++ .../data/blu.tiff | Bin .../data}/font.tiff | Bin .../data/processblu.py | 0 examples/board_hd77480/font.h | 1070 +++++++++++++++++ examples/parts/ac_input.c | 45 + examples/parts/ac_input.h | 49 + examples/parts/hd44780.c | 374 ++++++ examples/parts/hd44780.h | 137 +++ examples/parts/hd44780_glut.c | 151 +++ examples/parts/hd44780_glut.h | 38 + 27 files changed, 2596 insertions(+), 890 deletions(-) delete mode 100644 examples/board_charlcd/ac_input.c delete mode 100644 examples/board_charlcd/ac_input.h delete mode 100644 examples/board_charlcd/atmega48_charlcd.c delete mode 100644 examples/board_charlcd/atmega48_lcd.c delete mode 100644 examples/board_charlcd/atmega48_lcd.h delete mode 100644 examples/board_charlcd/charlcd.c delete mode 100644 examples/board_charlcd/hd44780.c delete mode 100644 examples/board_charlcd/hd44780.h delete mode 100644 examples/board_charlcd/hd44780_glut.c delete mode 100644 examples/board_charlcd/hd44780_glut.h rename examples/{board_charlcd => board_hd77480}/Makefile (63%) create mode 100644 examples/board_hd77480/README create mode 100644 examples/board_hd77480/atmega48_charlcd.c create mode 100644 examples/board_hd77480/avr_hd44780.c create mode 100644 examples/board_hd77480/avr_hd44780.h create mode 100644 examples/board_hd77480/avr_hd44780_conf.h create mode 100644 examples/board_hd77480/charlcd.c rename examples/{board_charlcd => board_hd77480}/data/blu.tiff (100%) rename examples/{board_charlcd => board_hd77480/data}/font.tiff (100%) rename examples/{board_charlcd => board_hd77480}/data/processblu.py (100%) create mode 100644 examples/board_hd77480/font.h create mode 100644 examples/parts/ac_input.c create mode 100644 examples/parts/ac_input.h create mode 100644 examples/parts/hd44780.c create mode 100644 examples/parts/hd44780.h create mode 100644 examples/parts/hd44780_glut.c create mode 100644 examples/parts/hd44780_glut.h diff --git a/examples/board_charlcd/ac_input.c b/examples/board_charlcd/ac_input.c deleted file mode 100644 index 29447f5..0000000 --- a/examples/board_charlcd/ac_input.c +++ /dev/null @@ -1,18 +0,0 @@ - -#include "sim_avr.h" -#include "ac_input.h" -#include "stdio.h" - -static avr_cycle_count_t switch_auto( struct avr_t * avr, avr_cycle_count_t when, void * param){ - ac_input_t * b = (ac_input_t *)param; - b->value = b->value == 0 ? 1 : 0; - avr_raise_irq( b->irq + IRQ_AC_OUT, b->value ); - return when + avr_usec_to_cycles(avr,10000); -} - -void ac_input_init(struct avr_t *avr, ac_input_t *b){ - b->irq = avr_alloc_irq(0,IRQ_AC_COUNT); - b->avr = avr; - b->value = 0; - avr_cycle_timer_register_usec(avr, 10000, switch_auto, b); -} diff --git a/examples/board_charlcd/ac_input.h b/examples/board_charlcd/ac_input.h deleted file mode 100644 index 07c2c4b..0000000 --- a/examples/board_charlcd/ac_input.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __AC_INPUT_H__ -#define __AC_INPUT_H__ - -#include "sim_irq.h" - -/* - * Simulates a 50hz changing signal - */ - -enum { - IRQ_AC_OUT = 0, - IRQ_AC_COUNT -}; - -typedef struct ac_input_t { - avr_irq_t * irq; - struct avr_t * avr; - uint8_t value; -} ac_input_t; - -void ac_input_init(struct avr_t * avr, ac_input_t * b); - -#endif diff --git a/examples/board_charlcd/atmega48_charlcd.c b/examples/board_charlcd/atmega48_charlcd.c deleted file mode 100644 index 993190a..0000000 --- a/examples/board_charlcd/atmega48_charlcd.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include -#include "stdlib.h" -#include "string.h" - -#include "atmega48_lcd.h" - -#include "avr_mcu_section.h" -AVR_MCU(F_CPU, "atmega48"); - -static uint8_t subsecct = 0; -static uint8_t hour = 0; -static uint8_t minute = 0; -static uint8_t second = 0; -static volatile uint8_t update_needed = 0; - -ISR( INT0_vect ){ - /* External interrupt on pin D2 */ - subsecct++; - if( subsecct == 50 ){ - second++; - update_needed = 1; - if(second ==60){ - minute++; - second = 0; - if(minute==60){ - minute =0; - hour++; - if(hour==24) hour =0; - } - } - } -} - -int main(){ - lcd_init(); - - - EICRA = (1< -#include "atmega48_lcd.h" -#include - -// sendet ein Datenbyte an das LCD - -void lcd_data(unsigned char temp1) -{ - unsigned char temp2 = temp1; - - LCD_PORT |= (1<> 4; - temp1 = temp1 & 0x0F; - LCD_PORT &= 0xF0; - LCD_PORT |= temp1; // setzen - lcd_enable(); - - temp2 = temp2 & 0x0F; - LCD_PORT &= 0xF0; - LCD_PORT |= temp2; // setzen - lcd_enable(); - - _delay_us(42); -} - -// sendet einen Befehl an das LCD - -void lcd_command(unsigned char temp1) -{ - unsigned char temp2 = temp1; - - LCD_PORT &= ~(1<> 4; // oberes Nibble holen - temp1 = temp1 & 0x0F; // maskieren - LCD_PORT &= 0xF0; - LCD_PORT |= temp1; // setzen - lcd_enable(); - - temp2 = temp2 & 0x0F; // unteres Nibble holen und maskieren - LCD_PORT &= 0xF0; - LCD_PORT |= temp2; // setzen - lcd_enable(); - - _delay_us(42); -} - -// erzeugt den Enable-Puls -void lcd_enable(void) -{ - // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen - // http://www.mikrocontroller.net/topic/81974#685882 - LCD_PORT |= (1< -#include -#include - -#include "sim_avr.h" -#include "avr_ioport.h" -#include "sim_elf.h" -#include "sim_gdb.h" -#include "sim_vcd_file.h" - -#include -#include -#include - -#include "SDL.h" -#include "SDL_image.h" - -#include "ac_input.h" -#include "hd44780.h" -#include "hd44780_glut.h" - -/* screen width, height, and bit depth */ -#define SCREEN_WIDTH 800 -#define SCREEN_HEIGHT 600 -#define SCREEN_BPP 16 - -int window; -avr_t * avr = NULL; -avr_vcd_t vcd_file; -ac_input_t ac_input; -hd44780_t hd44780; - -SDL_Surface *surface; - -static void * avr_run_thread( ){ - while(1){ - avr_run(avr); - } -} - -void Quit( int returnCode ) -{ - SDL_Quit( ); - exit( returnCode ); -} - -int resizeWindow( int width, int height ) -{ - if ( height == 0 ) height = 1; - glViewport( 0, 0, ( GLsizei )width, ( GLsizei )height ); - glMatrixMode( GL_PROJECTION ); - glLoadIdentity( ); - glOrtho(0, 800, 0, 600, 0, 10); - - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity( ); - - return 1; -} - -void handleKeyPress( SDL_keysym *keysym ) -{ - switch ( keysym->sym ) - { - case SDLK_ESCAPE: - Quit( 0 ); - break; - case SDLK_F1: - SDL_WM_ToggleFullScreen( surface ); - break; - default: - break; - } -} - -int initGL( GLvoid ) -{ - glEnable( GL_TEXTURE_2D ); - glShadeModel( GL_SMOOTH ); - - glClearColor( 0.8f, 0.8f, 0.8f, 1.0f ); - glColor4f( 1.0f,1.0f,1.0f,1.0f); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - glEnable( GL_BLEND); - - glClearDepth( 1.0f ); - - glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); - - hd44780_gl_init(); - - return 1; -} - -int drawGLScene( GLvoid ) -{ - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - glMatrixMode(GL_MODELVIEW); // Select modelview matrix - glPushMatrix(); - glLoadIdentity(); // Start with an identity matrix - glScalef(3,3,1); - glTranslatef( 89.66f,150,0); - hd44780_gl_draw( &hd44780 ); - glPopMatrix(); - SDL_GL_SwapBuffers(); - return 1; -} - - -int main(int argc, char *argv[]) -{ - elf_firmware_t f; - const char * fname = "atmega48_charlcd.axf"; - char path[256]; - sprintf(path, "%s/%s", dirname(argv[0]), fname); - printf("Firmware pathname is %s\n", path); - elf_read_firmware(path, &f); - - printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu); - - avr = avr_make_mcu_by_name(f.mmcu); - if (!avr) { - fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu); - exit(1); - } - - avr_init(avr); - avr_load_firmware(avr,&f); - ac_input_init(avr, &ac_input); - avr_connect_irq( - ac_input.irq + IRQ_AC_OUT, - avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('D'),2)); - - hd44780_init(avr, &hd44780); -/* hd44780_print2x16(&hd44780); */ - - /* Connect Data Lines to Port B, 0-3 */ - for( int i =0; i<4;i++){ - avr_irq_register_notify( - avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), i), - hd44780_data_changed_hook, - &hd44780); - } - /* Connect Cmd Lines */ - for( int i =4; i<7;i++){ - avr_irq_register_notify( - avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), i), - hd44780_cmd_changed_hook, - &hd44780); - } - - avr_vcd_init(avr, "gtkwave_output.vcd", &vcd_file, 100 /* usec */); - avr_vcd_add_signal(&vcd_file, - avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_PIN_ALL), 8 /* bits */ , - "portb" ); - - avr_vcd_add_signal(&vcd_file, - ac_input.irq + IRQ_AC_OUT, 1, "ac_input"); - - avr_vcd_start(&vcd_file); - - //avr_gdb_init(avr); - //avr->state = cpu_Stopped; - - - avr_vcd_stop(&vcd_file); - - - if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { - fprintf( stderr, "Video initialization failed: %s\n",SDL_GetError( ) ); - Quit( 1 ); - } - int done =0, isActive=1; - SDL_Event event; - int videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE | SDL_RESIZABLE | SDL_HWSURFACE | SDL_HWACCEL; - SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); - surface = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, videoFlags ); - SDL_WM_SetCaption("HD44780 Simulation",""); - if( !surface ) { - fprintf( stderr, "Video mode set failed: %s\n", SDL_GetError( ) ); - Quit( 1 ); - } - initGL( ); - resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT); - - pthread_t run; - pthread_create(&run, NULL, avr_run_thread, NULL); - - while(!done){ - while ( SDL_PollEvent( &event ) ) - { - switch( event.type ) - { - case SDL_ACTIVEEVENT: - if ( event.active.gain == 0 ) - isActive = 0; - else - isActive = 1; - break; - case SDL_VIDEORESIZE: - /* handle resize event */ - surface = SDL_SetVideoMode( event.resize.w, - event.resize.h, - 16, videoFlags ); - if ( !surface ) - { - fprintf( stderr, "Could not get a surface after resize: %s\n", SDL_GetError( ) ); - Quit( 1 ); - } - resizeWindow( event.resize.w, event.resize.h ); - break; - case SDL_KEYDOWN: - /* handle key presses */ - handleKeyPress( &event.key.keysym ); - break; - case SDL_QUIT: - /* handle quit requests */ - done = 1; - break; - default: - break; - } - } - drawGLScene(); - } - return 0; - -} diff --git a/examples/board_charlcd/hd44780.c b/examples/board_charlcd/hd44780.c deleted file mode 100644 index 46178e8..0000000 --- a/examples/board_charlcd/hd44780.c +++ /dev/null @@ -1,185 +0,0 @@ -#include "hd44780.h" -#include -#include -#include -#include - -void debug_print( const char* format, ... ) { - - va_list args; - va_start( args, format ); - #ifdef HD44780_DEBUG - vprintf( format, args ); - #endif - va_end( args ); -} - -int check_flag( hd44780_t *b, int flag){ - return (b->flags>>flag)&1; -} - -void reset_cursor( hd44780_t *b){ - b->cursor = b->ddram; -} - -void clear_screen( hd44780_t *b){ - memset(b->ddram,' ',80); -} - -void handle_function_8bit( hd44780_t *b, int realportstate ){ - debug_print("handle_function_8bit realportstate 0x%x\n",realportstate); - /* - if( realportstate == 0x22){ - debug_print("Activating 4Bit Mode\n"); - b->mode_4bit = 1; - } - */ - if( realportstate == 1) { - clear_screen(b); - debug_print("Clear Screen\n"); - } - if( realportstate >> 1 == 1) { - debug_print("Move Cursor to startpos\n"); - reset_cursor(b); - } - if( realportstate >> 2 == 1) { - debug_print("Setting I/S mode\n"); - b->flags &= ~(3<flags |= (realportstate & 3)<> 3 == 1) { - debug_print("Setting Display/Cursor Mode\n"); - b->flags &= ~(7<flags |= realportstate&7 << HD44780_FLAG_B; // Set B,C,D bits - } - if( realportstate >> 4 == 1) { - debug_print("Moving Display/Cursor Mode\n"); - b->flags &= ~(3<flags |= (realportstate & 3)<> 5 == 1) { - debug_print("Functions\n"); - b->flags &= ~(7<flags |= (realportstate>>2)&7 << HD44780_FLAG_F; // Set F,N,DL bits - if( !check_flag(b, HD44780_FLAG_D_L) ){ - debug_print("Enabling 4Bit Mode\n"); - b->mode_4bit = 1; - } - } - if( realportstate >> 6 == 1) printf("Set CGRAM Address\n"); - if( realportstate >> 7 == 1) { - debug_print("Set DDRAM Address\n"); - b->cursor = b->ddram + (realportstate & 0x7f); - } - debug_print("Flags are 0x%x\n",b->flags); -} - -void handle_data_8bit( hd44780_t *b, int realportstate ){ - /* printf("handle_data_8bit realportstate 0x%x\n",realportstate); */ - *(b->cursor) = realportstate & 0xff; - if( !check_flag(b, HD44780_FLAG_S_C) ){ - // Move Cursor - if( check_flag(b, HD44780_FLAG_I_D) ){ - b->cursor++; - } - else{ - b->cursor--; - } - } - else { - printf("!! NOT IMPLEMENTED\n"); - // Move Display - if( check_flag(b, HD44780_FLAG_R_L) ){ - //Move right - - } - else { - // Move left - } - } - if( b->cursor < b->ddram || b->cursor > b->ddram+80){ - debug_print("Cursor out of range!\n"); - reset_cursor(b); - } - #ifdef HD44780_DEBUG - hd44780_print2x16( b ); - #endif -} - -void hd44780_init( struct avr_t *avr, struct hd44780_t * b) { - b->irq = avr_alloc_irq(0,IRQ_HD44780_COUNT); - b->portstate = 0x00; - b->mode_4bit = 0; - b->four_bit_cache = 0; - b->inits_recv = 0; - b->flags = 0; - reset_cursor(b); - clear_screen(b); -} - -void hd44780_print2x16( struct hd44780_t *b){ - printf("/******************\\\n| "); - fwrite( b->ddram, 1, 16, stdout); - printf(" |\n| "); -// fputc('\n',stdout); - fwrite( b->ddram + 0x40, 1, 16, stdout); - printf(" |\n\\******************/\n"); -} - -void hd44780_data_changed_hook( struct avr_irq_t * irq, uint32_t value, void *param){ - hd44780_t *b = (hd44780_t *)param; - int datapos = -1; - if( irq->irq == DATA_PIN_0) datapos = 0; - if( irq->irq == DATA_PIN_1) datapos = 1; - if( irq->irq == DATA_PIN_2) datapos = 2; - if( irq->irq == DATA_PIN_3) datapos = 3; - if( irq->irq == DATA_PIN_4) datapos = 4; - if( irq->irq == DATA_PIN_5) datapos = 5; - if( irq->irq == DATA_PIN_6) datapos = 6; - if( irq->irq == DATA_PIN_7) datapos = 7; - if( datapos >= 0){ - if( value == 1) b->portstate |= 1<portstate &= ~(1<irq == RS_PIN){ - b->rs=value; - } - if( irq->irq == RW_PIN){ - b->rw=value; - } - if( irq->irq == ENABLE_PIN && value == 0){ - debug_print("enable pulse! portstate 0x%x\n", b->portstate); - if( b->inits_recv < 3 ){ - if( b->portstate == 0x30 ){ - debug_print("Init received\n"); - b->inits_recv++; - } - else debug_print("Uuups, received command before fully initialized?\n"); - } - else { - int realportstate=0; - int received = 1; - if( b->mode_4bit == 1) b->four_bit_cache = b->portstate, b->mode_4bit++,received=0; - else if( b->mode_4bit == 2) { - realportstate = (b->four_bit_cache&0xf0) | (b->portstate&0xf0)>>4; - b->mode_4bit=1; - } - else realportstate = b->portstate; - debug_print("four bit cache is 0x%x\n",b->four_bit_cache); - - if(received){ - if( !b->rs ) handle_function_8bit( b, realportstate ); - else handle_data_8bit( b, realportstate ); - } - } - } -// printf("pin %i is now %i, portstate 0x%x\n", irq->irq, value, b->portstate); -} - - - diff --git a/examples/board_charlcd/hd44780.h b/examples/board_charlcd/hd44780.h deleted file mode 100644 index 4b4ce12..0000000 --- a/examples/board_charlcd/hd44780.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef __HD44780_H__ -#define __HD44780_H__ - -#include "sim_irq.h" - -/****************** - * Simulates a HD44780 controlled character LED. - * All the Data Pins have to be on the same Port. - * All the Cmd Pins have to be on the same Port. In 4 Bit mode, - * they can share one Port. - * For output of the display contents, use hd44780_print2x16 or a opengl function. - ******************/ - -#define ENABLE_PIN 5 -#define RW_PIN 6 -#define RS_PIN 4 -/* Use -1 for not connected */ -#define DATA_PIN_0 -1 -#define DATA_PIN_1 -1 -#define DATA_PIN_2 -1 -#define DATA_PIN_3 -1 -#define DATA_PIN_4 0 -#define DATA_PIN_5 1 -#define DATA_PIN_6 2 -#define DATA_PIN_7 3 - -/* #define HD44780_DEBUG */ - -enum { - HD44780_FLAG_F = 0, //5x7 Font, 5x10 Font - HD44780_FLAG_N, //1-zeiliges Display, 2/4-zeiliges Display - HD44780_FLAG_D_L, //4-Bit Interface, 8-Bit Interface - HD44780_FLAG_R_L, // Nach links schieben,Nach rechts schieben - HD44780_FLAG_S_C, //Cursor bewegen, Displayinhalt schieben - HD44780_FLAG_B, //Cursor blinkt nicht, Cursor blinkt - HD44780_FLAG_C, //Cursor aus,Cursor an - HD44780_FLAG_D, //Display aus,Display an - HD44780_FLAG_S, //Displayinhalt fest, Displayinhalt weiterschieben - HD44780_FLAG_I_D -}; - -enum { - IRQ_HD44780_IN = 0, - IRQ_HD44780_COUNT -}; - - -typedef struct hd44780_t { - avr_irq_t * irq; - struct avr_t * avr; - char *cursor; - char ddram[80]; - char cgram[64]; - uint32_t rw; /* R/W pin */ - uint32_t rs; /* RS pin */ - int portstate; - char mode_4bit; /* 0=disabled, 1=waitingforfirstnibble, 2=waitingforsecondnibble */ - uint32_t flags; - int four_bit_cache; - char inits_recv; /* num of init sequences received */ -} hd44780_t; - -void hd44780_init( struct avr_t *avr, struct hd44780_t * b); -void hd44780_print2x16( struct hd44780_t *b); - -void hd44780_data_changed_hook( struct avr_irq_t * irq, uint32_t value, void *param); -void hd44780_cmd_changed_hook( struct avr_irq_t * irq, uint32_t value, void *param); - -#endif diff --git a/examples/board_charlcd/hd44780_glut.c b/examples/board_charlcd/hd44780_glut.c deleted file mode 100644 index 4f9dee8..0000000 --- a/examples/board_charlcd/hd44780_glut.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "hd44780_glut.h" - -#include "SDL.h" -#include "SDL_image.h" -#include -#include - -static GLuint font_texture; -static int charwidth = 5; -static int charheight = 7; - -void hd44780_gl_init(){ - SDL_Surface *image; - image = IMG_Load("font.tiff"); - if( !image) { - printf("Problem loading texture\n"); - return; - } - glGenTextures(1,&font_texture); - glBindTexture(GL_TEXTURE_2D, font_texture); -/* printf("imagew %i, imageh %i, bytesperpixel %i\n", image->w, image->h, image->format->BytesPerPixel); */ - glTexImage2D( GL_TEXTURE_2D, 0, 4, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glScalef( 1.0f/(GLfloat)image->w, 1.0f/(GLfloat)image->h,1.0f); - - SDL_FreeSurface(image); - glMatrixMode(GL_MODELVIEW); -} - -void glputchar(char c){ - int index = c; - int left = index * charwidth; - int right = index*charwidth+charwidth; - int top = 0; - int bottom =7; - - glDisable(GL_TEXTURE_2D); - glColor3f( 0.0f, 1.0f, 0.0f); - glBegin( GL_QUADS); - glVertex3i( 5, 7, 0 ); - glVertex3i( 0, 7, 0 ); - glVertex3i( 0, 0, 0 ); - glVertex3i( 5, 0, 0 ); - glEnd( ); - - glEnable(GL_TEXTURE_2D); - glColor3f( 1.0f, 1.0f, 1.0f); - glBindTexture(GL_TEXTURE_2D, font_texture); - glBegin( GL_QUADS); - glTexCoord2i(right,top); glVertex3i( 5, 7, 0 ); - glTexCoord2i(left, top); glVertex3i( 0, 7, 0 ); - glTexCoord2i(left, bottom); glVertex3i( 0, 0, 0 ); - glTexCoord2i(right,bottom); glVertex3i( 5, 0, 0 ); - glEnd( ); - -} - -void glputstr( char *str){ - while( *(++str) != 0 ){ - glputchar(*str); - glTranslatef(6,0,0); - } -} - -void hd44780_gl_draw( hd44780_t *b){ - int rows = 16; - int lines = 2; - int border = 3; - glDisable(GL_TEXTURE_2D); - glColor3f(0.0f,0.4f,0.0f); - glTranslatef(0,-8,0); - glBegin(GL_QUADS); - glVertex3f( rows*charwidth + (rows-1) + border, -border,0); - glVertex3f( - border, -border,0); - glVertex3f( - border, lines*charheight + (lines-1)+border,0); - glVertex3f( rows*charwidth + (rows-1) + border, lines*charheight + (lines-1)+border,0); - glEnd(); - glTranslatef(0,8,0); - glColor3f(1.0f,1.0f,1.0f); - for( int i=0; i<16; i++) { - glputchar( b->ddram[i] ); - glTranslatef(6,0,0); - } - glTranslatef(-96,-8,0); - for( int i=0; i<16; i++) { - glputchar( b->ddram[i+0x40] ); - glTranslatef(6,0,0); - } - -} diff --git a/examples/board_charlcd/hd44780_glut.h b/examples/board_charlcd/hd44780_glut.h deleted file mode 100644 index 53d9403..0000000 --- a/examples/board_charlcd/hd44780_glut.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __HD44780_GLUT_H__ -#define __HD44780_GLUT_H__ - -#include "hd44780.h" - -void hd44780_gl_draw( hd44780_t *b); - -void hd44780_gl_init(); - -#endif diff --git a/examples/board_charlcd/Makefile b/examples/board_hd77480/Makefile similarity index 63% rename from examples/board_charlcd/Makefile rename to examples/board_hd77480/Makefile index 8da9583..04a18d5 100644 --- a/examples/board_charlcd/Makefile +++ b/examples/board_hd77480/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2008, 2009 Michel Pollet +# Copyright 2008-2011 Michel Pollet # # This file is part of simavr. # @@ -32,30 +32,15 @@ VPATH = . VPATH += ../parts LDFLAGS += -lpthread -LDFLAGS += -lGLU -LDFLAGS += -lGL -LDFLAGS += `sdl-config --libs` -LDFLAGS += -lSDL_image +ifneq (${shell uname}, Darwin) +LDFLAGS += -lGL -lglut +else +LDFLAGS += -framework GLUT -framework OpenGL +endif -CFLAGS = `sdl-config --cflags` -#ifneq (${shell uname}, Darwin) -#else -#LDFLAGS += -framework GLUT -framework OpenGL -#endif all: obj atmega48_charlcd.axf ${board} -atmega48_charlcd.axf: atmega48_charlcd.c atmega48_lcd.c atmega48_lcd.h - @echo AVR-CC ${<} - ${AVR}gcc -Wall -gdwarf-2 -Os -std=gnu99 \ - -mmcu=atmega48 \ - -DF_CPU=8000000 \ - -fno-inline-small-functions \ - -ffunction-sections -fdata-sections \ - -Wl,--relax,--gc-sections \ - -Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000 \ - -I../include -I../../include \ - atmega48_charlcd.c atmega48_lcd.c -o atmega48_charlcd.axf - @${AVR}size ${@}|sed '1d' +atmega48_charlcd.axf: atmega48_charlcd.c include ${simavr}/Makefile.common diff --git a/examples/board_hd77480/README b/examples/board_hd77480/README new file mode 100644 index 0000000..0ef3b59 --- /dev/null +++ b/examples/board_hd77480/README @@ -0,0 +1,21 @@ +board_hd44780 + +(C) 2011 Michel Pollet +With thanks to Luki + +This sample code is derivated from a patch sent by Luki, however it was mostly +in german, and was usinf the SDL library. Also the implementation of the LCD +itself had several shortcomings. + +Therefore it was almost entirely rewritten from scratch the LCD was extended +and made as compliant as it is practical, and the sample code itself was +stripped of SDL. Also the german AVR LCD driver was replaced with the +avr-libc one, a much more complete one. + +This example demonstrated how to write a "part' that provide both a way to +visualize what your code is doing, but also provide extra data you can +visualize in gtkwave; so the LCD "part" exports quite a few IRQs that can +be used to help you trace and debug your own code. + +Make sure to run this program and visualize the pretty curves. + \ No newline at end of file diff --git a/examples/board_hd77480/atmega48_charlcd.c b/examples/board_hd77480/atmega48_charlcd.c new file mode 100644 index 0000000..95c1e96 --- /dev/null +++ b/examples/board_hd77480/atmega48_charlcd.c @@ -0,0 +1,114 @@ +/* + atmega48_charlcd.c + + Copyright Luki + Copyright 2011 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#undef F_CPU +#define F_CPU 10000000 + +#include +#include +#include +#include +#include +#include +#include + +//#include "avr_defines.h" + +#include "avr_mcu_section.h" +AVR_MCU(F_CPU, "atmega48"); + +static uint8_t subsecct = 0; +static uint8_t hour = 0; +static uint8_t minute = 0; +static uint8_t second = 0; +static volatile uint8_t update_needed = 0; + +#include "avr_hd44780.c" + +ISR( INT0_vect ) +{ + /* External interrupt on pin D2 */ + subsecct++; + if (subsecct == 50) { + second++; + subsecct = 0; + update_needed = 1; + if (second == 60) { + minute++; + second = 0; + if (minute == 60) { + minute = 0; + hour++; + if (hour == 24) + hour = 0; + } + } + } +} + +int main() +{ + hd44780_init(); + /* + * Clear the display. + */ + hd44780_outcmd(HD44780_CLR); + hd44780_wait_ready(1); // long wait + + /* + * Entry mode: auto-increment address counter, no display shift in + * effect. + */ + hd44780_outcmd(HD44780_ENTMODE(1, 0)); + hd44780_wait_ready(0); + + /* + * Enable display, activate non-blinking cursor. + */ + hd44780_outcmd(HD44780_DISPCTL(1, 1, 0)); + hd44780_wait_ready(0); + + EICRA = (1 << ISC00); + EIMSK = (1 << INT0); + + sei(); + + while (1) { + while (!update_needed) + sleep_mode(); + update_needed = 0; + char buffer[16]; + + hd44780_outcmd(HD44780_CLR); + hd44780_wait_ready(1); // long wait + hd44780_outcmd(HD44780_DDADDR(4)); + hd44780_wait_ready(0); + sprintf(buffer, "%2d:%02d:%02d", hour, minute, second); + + char *s = buffer; + while (*s) { + hd44780_outdata(*s++); + hd44780_wait_ready(0); + } + } + +} diff --git a/examples/board_hd77480/avr_hd44780.c b/examples/board_hd77480/avr_hd44780.c new file mode 100644 index 0000000..7901fa5 --- /dev/null +++ b/examples/board_hd77480/avr_hd44780.c @@ -0,0 +1,216 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch + * ---------------------------------------------------------------------------- + * + * HD44780 LCD display driver + * + * The LCD controller is used in 4-bit mode with a full bi-directional + * interface (i.e. R/~W is connected) so the busy flag can be read. + * + * $Id: hd44780.c 2002 2009-06-25 20:21:16Z joerg_wunsch $ + */ + +#include "avr_hd44780_conf.h" + +#include +#include + +#include +#include + +#include "avr_hd44780.h" + +#define GLUE(a, b) a##b + +/* single-bit macros, used for control bits */ +#define SET_(what, p, m) GLUE(what, p) |= (1 << (m)) +#define CLR_(what, p, m) GLUE(what, p) &= ~(1 << (m)) +#define GET_(/* PIN, */ p, m) GLUE(PIN, p) & (1 << (m)) +#define SET(what, x) SET_(what, x) +#define CLR(what, x) CLR_(what, x) +#define GET(/* PIN, */ x) GET_(x) + +/* nibble macros, used for data path */ +#define ASSIGN_(what, p, m, v) GLUE(what, p) = (GLUE(what, p) & \ + ~((1 << (m)) | (1 << ((m) + 1)) | \ + (1 << ((m) + 2)) | (1 << ((m) + 3)))) | \ + ((v) << (m)) +#define READ_(what, p, m) (GLUE(what, p) & ((1 << (m)) | (1 << ((m) + 1)) | \ + (1 << ((m) + 2)) | (1 << ((m) + 3)))) >> (m) +#define ASSIGN(what, x, v) ASSIGN_(what, x, v) +#define READ(what, x) READ_(what, x) + +#define HD44780_BUSYFLAG 0x80 + +/* + * Send one pulse to the E signal (enable). Mind the timing + * constraints. If readback is set to true, read the HD44780 data + * pins right before the falling edge of E, and return that value. + */ +static inline uint8_t +hd44780_pulse_e(bool readback) __attribute__((always_inline)); + +static inline uint8_t +hd44780_pulse_e(bool readback) +{ + uint8_t x; + + SET(PORT, HD44780_E); + /* + * Guarantee at least 500 ns of pulse width. For high CPU + * frequencies, a delay loop is used. For lower frequencies, NOPs + * are used, and at or below 1 MHz, the native pulse width will + * already be 1 us or more so no additional delays are needed. + */ +#if F_CPU > 4000000UL + _delay_us(0.5); +#else + /* + * When reading back, we need one additional NOP, as the value read + * back from the input pin is sampled close to the beginning of a + * CPU clock cycle, while the previous edge on the output pin is + * generated towards the end of a CPU clock cycle. + */ + if (readback) + __asm__ volatile("nop"); +# if F_CPU > 1000000UL + __asm__ volatile("nop"); +# if F_CPU > 2000000UL + __asm__ volatile("nop"); + __asm__ volatile("nop"); +# endif /* F_CPU > 2000000UL */ +# endif /* F_CPU > 1000000UL */ +#endif + if (readback) + x = READ(PIN, HD44780_D4); + else + x = 0; + CLR(PORT, HD44780_E); + + return x; +} + +/* + * Send one nibble out to the LCD controller. + */ +static void +hd44780_outnibble(uint8_t n, uint8_t rs) +{ + CLR(PORT, HD44780_RW); + if (rs) + SET(PORT, HD44780_RS); + else + CLR(PORT, HD44780_RS); + ASSIGN(PORT, HD44780_D4, n); + (void)hd44780_pulse_e(false); +} + +/* + * Send one byte to the LCD controller. As we are in 4-bit mode, we + * have to send two nibbles. + */ +void +hd44780_outbyte(uint8_t b, uint8_t rs) +{ + hd44780_outnibble(b >> 4, rs); + hd44780_outnibble(b & 0xf, rs); +} + +/* + * Read one nibble from the LCD controller. + */ +static uint8_t +hd44780_innibble(uint8_t rs) +{ + uint8_t x; + + SET(PORT, HD44780_RW); + ASSIGN(DDR, HD44780_D4, 0x00); + if (rs) + SET(PORT, HD44780_RS); + else + CLR(PORT, HD44780_RS); + x = hd44780_pulse_e(true); + ASSIGN(DDR, HD44780_D4, 0x0F); + CLR(PORT, HD44780_RW); + + return x; +} + +/* + * Read one byte (i.e. two nibbles) from the LCD controller. + */ +uint8_t +hd44780_inbyte(uint8_t rs) +{ + uint8_t x; + + x = hd44780_innibble(rs) << 4; + x |= hd44780_innibble(rs); + + return x; +} + +/* + * Wait until the busy flag is cleared. + */ +void +hd44780_wait_ready(bool longwait) +{ +#if USE_BUSY_BIT + while (hd44780_incmd() & HD44780_BUSYFLAG) ; +#else + if (longwait) + _delay_ms(1.52); + else + _delay_us(37); +#endif +} + +/* + * Initialize the LCD controller. + * + * The initialization sequence has a mandatory timing so the + * controller can safely recognize the type of interface desired. + * This is the only area where timed waits are really needed as + * the busy flag cannot be probed initially. + */ +void +hd44780_init(void) +{ + SET(DDR, HD44780_RS); + SET(DDR, HD44780_RW); + SET(DDR, HD44780_E); + ASSIGN(DDR, HD44780_D4, 0x0F); + + _delay_ms(15); /* 40 ms needed for Vcc = 2.7 V */ + hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0); + _delay_ms(4.1); + hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0); + _delay_ms(0.1); + hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0); + _delay_us(40); /* 37 is too short */ + + hd44780_outnibble(HD44780_FNSET(0, 1, 0) >> 4, 0); + hd44780_wait_ready(false); + hd44780_outcmd(HD44780_FNSET(0, 1, 0)); + hd44780_wait_ready(false); + hd44780_outcmd(HD44780_DISPCTL(0, 0, 0)); + hd44780_wait_ready(false); +} + +/* + * Prepare the LCD controller pins for powerdown. + */ +void +hd44780_powerdown(void) +{ + ASSIGN(PORT, HD44780_D4, 0); + CLR(PORT, HD44780_RS); + CLR(PORT, HD44780_RW); + CLR(PORT, HD44780_E); +} diff --git a/examples/board_hd77480/avr_hd44780.h b/examples/board_hd77480/avr_hd44780.h new file mode 100644 index 0000000..6d3d978 --- /dev/null +++ b/examples/board_hd77480/avr_hd44780.h @@ -0,0 +1,105 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch + * ---------------------------------------------------------------------------- + * + * HD44780 LCD display driver + * + * $Id: hd44780.h 2002 2009-06-25 20:21:16Z joerg_wunsch $ + */ + +/* + * Send byte b to the LCD. rs is the RS signal (register select), 0 + * selects instruction register, 1 selects the data register. + */ +void hd44780_outbyte(uint8_t b, uint8_t rs); + +/* + * Read one byte from the LCD controller. rs is the RS signal, 0 + * selects busy flag (bit 7) and address counter, 1 selects the data + * register. + */ +uint8_t hd44780_inbyte(uint8_t rs); + +/* + * Wait for the busy flag to clear. + */ +void hd44780_wait_ready(bool islong); + +/* + * Initialize the LCD controller hardware. + */ +void hd44780_init(void); + +/* + * Prepare the LCD controller pins for powerdown. + */ +void hd44780_powerdown(void); + + +/* Send a command to the LCD controller. */ +#define hd44780_outcmd(n) hd44780_outbyte((n), 0) + +/* Send a data byte to the LCD controller. */ +#define hd44780_outdata(n) hd44780_outbyte((n), 1) + +/* Read the address counter and busy flag from the LCD. */ +#define hd44780_incmd() hd44780_inbyte(0) + +/* Read the current data byte from the LCD. */ +#define hd44780_indata() hd44780_inbyte(1) + + +/* Clear LCD display command. */ +#define HD44780_CLR \ + 0x01 + +/* Home cursor command. */ +#define HD44780_HOME \ + 0x02 + +/* + * Select the entry mode. inc determines whether the address counter + * auto-increments, shift selects an automatic display shift. + */ +#define HD44780_ENTMODE(inc, shift) \ + (0x04 | ((inc)? 0x02: 0) | ((shift)? 1: 0)) + +/* + * Selects disp[lay] on/off, cursor on/off, cursor blink[ing] + * on/off. + */ +#define HD44780_DISPCTL(disp, cursor, blink) \ + (0x08 | ((disp)? 0x04: 0) | ((cursor)? 0x02: 0) | ((blink)? 1: 0)) + +/* + * With shift = 1, shift display right or left. + * With shift = 0, move cursor right or left. + */ +#define HD44780_SHIFT(shift, right) \ + (0x10 | ((shift)? 0x08: 0) | ((right)? 0x04: 0)) + +/* + * Function set. if8bit selects an 8-bit data path, twoline arranges + * for a two-line display, font5x10 selects the 5x10 dot font (5x8 + * dots if clear). + */ +#define HD44780_FNSET(if8bit, twoline, font5x10) \ + (0x20 | ((if8bit)? 0x10: 0) | ((twoline)? 0x08: 0) | \ + ((font5x10)? 0x04: 0)) + +/* + * Set the next character generator address to addr. + */ +#define HD44780_CGADDR(addr) \ + (0x40 | ((addr) & 0x3f)) + +/* + * Set the next display address to addr. + */ +#define HD44780_DDADDR(addr) \ + (0x80 | ((addr) & 0x7f)) + diff --git a/examples/board_hd77480/avr_hd44780_conf.h b/examples/board_hd77480/avr_hd44780_conf.h new file mode 100644 index 0000000..b01bc7d --- /dev/null +++ b/examples/board_hd77480/avr_hd44780_conf.h @@ -0,0 +1,23 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch + * ---------------------------------------------------------------------------- + * + * General stdiodemo defines + * + * $Id: defines.h 2186 2010-09-22 10:25:15Z aboyapati $ + */ + +/* HD44780 LCD port connections */ +#define HD44780_RW B, 6 +#define HD44780_E B, 5 +#define HD44780_RS B, 4 +/* The data bits have to be not only in ascending order but also consecutive. */ +#define HD44780_D4 B, 0 + +/* Whether to read the busy flag, or fall back to + worst-time delays. */ +#define USE_BUSY_BIT 1 diff --git a/examples/board_hd77480/charlcd.c b/examples/board_hd77480/charlcd.c new file mode 100644 index 0000000..a7c118d --- /dev/null +++ b/examples/board_hd77480/charlcd.c @@ -0,0 +1,246 @@ +/* + charlcd.c + + Copyright Luki + Copyright 2011 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#include +#include +#include + +#include "sim_avr.h" +#include "avr_ioport.h" +#include "sim_elf.h" +#include "sim_gdb.h" +#include "sim_vcd_file.h" + +#if __APPLE__ +#include +#else +#include +#endif +#include + +#include "ac_input.h" +#include "hd44780_glut.h" + + +//float pixsize = 16; +int window; + +avr_t * avr = NULL; +avr_vcd_t vcd_file; +ac_input_t ac_input; +hd44780_t hd44780; + +int color = 0; +uint32_t colors[][4] = { + { 0x00aa00ff, 0x00cc00ff, 0x000000ff, 0x00000055 }, // fluo green + { 0xaa0000ff, 0xcc0000ff, 0x000000ff, 0x00000055 }, // red +}; + +static void * +avr_run_thread( + void * ignore) +{ + while (1) { + avr_run(avr); + } +} + +void keyCB( + unsigned char key, int x, int y) /* called on key press */ +{ + switch (key) { + case 'q': + avr_vcd_stop(&vcd_file); + exit(0); + break; + case 'r': + printf("Starting VCD trace; press 's' to stop\n"); + avr_vcd_start(&vcd_file); + break; + case 's': + printf("Stopping VCD trace\n"); + avr_vcd_stop(&vcd_file); + break; + } +} + + +void displayCB(void) /* function called whenever redisplay needed */ +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_MODELVIEW); // Select modelview matrix + glPushMatrix(); + glLoadIdentity(); // Start with an identity matrix + glScalef(3, 3, 1); + + hd44780_gl_draw( + &hd44780, + colors[color][0], /* background */ + colors[color][1], /* character background */ + colors[color][2], /* text */ + colors[color][3] /* shadow */ ); + glPopMatrix(); + glutSwapBuffers(); +} + +// gl timer. if the lcd is dirty, refresh display +void timerCB(int i) +{ + static int oldstate = -1; + // restart timer + glutTimerFunc(1000/64, timerCB, 0); + glutPostRedisplay(); +} + +int +initGL(int w, int h) +{ + // Set up projection matrix + glMatrixMode(GL_PROJECTION); // Select projection matrix + glLoadIdentity(); // Start with an identity matrix + glOrtho(0, w, 0, h, 0, 10); + glScalef(1,-1,1); + glTranslatef(0, -1 * h, 0); + + glutDisplayFunc(displayCB); /* set window's display callback */ + glutKeyboardFunc(keyCB); /* set window's key callback */ + glutTimerFunc(1000 / 24, timerCB, 0); + + glEnable(GL_TEXTURE_2D); + glShadeModel(GL_SMOOTH); + + glClearColor(0.8f, 0.8f, 0.8f, 1.0f); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + hd44780_gl_init(); + + return 1; +} + +int +main( + int argc, + char *argv[]) +{ + elf_firmware_t f; + const char * fname = "atmega48_charlcd.axf"; + char path[256]; + sprintf(path, "%s/%s", dirname(argv[0]), fname); + printf("Firmware pathname is %s\n", path); + elf_read_firmware(path, &f); + + printf("firmware %s f=%d mmcu=%s\n", fname, (int) f.frequency, f.mmcu); + + avr = avr_make_mcu_by_name(f.mmcu); + if (!avr) { + fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu); + exit(1); + } + + avr_init(avr); + avr_load_firmware(avr, &f); + ac_input_init(avr, &ac_input); + avr_connect_irq(ac_input.irq + IRQ_AC_OUT, avr_io_getirq(avr, + AVR_IOCTL_IOPORT_GETIRQ('D'), 2)); + + hd44780_init(avr, &hd44780, 20, 4); + + /* Connect Data Lines to Port B, 0-3 */ + /* These are bidirectional too */ + for (int i = 0; i < 4; i++) { + avr_irq_t * iavr = avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), i); + avr_irq_t * ilcd = hd44780.irq + IRQ_HD44780_D4 + i; + // AVR -> LCD + avr_connect_irq(iavr, ilcd); + // LCD -> AVR + avr_connect_irq(ilcd, iavr); + } + avr_connect_irq( + avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 4), + hd44780.irq + IRQ_HD44780_RS); + avr_connect_irq( + avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 5), + hd44780.irq + IRQ_HD44780_E); + avr_connect_irq( + avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 6), + hd44780.irq + IRQ_HD44780_RW); + + + avr_vcd_init(avr, "gtkwave_output.vcd", &vcd_file, 10 /* usec */); + avr_vcd_add_signal(&vcd_file, + avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_PIN_ALL), + 4 /* bits */, "D4-D7"); + avr_vcd_add_signal(&vcd_file, + avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 4), + 1 /* bits */, "RS"); + avr_vcd_add_signal(&vcd_file, + avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 5), + 1 /* bits */, "E"); + avr_vcd_add_signal(&vcd_file, + avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 6), + 1 /* bits */, "RW"); + avr_vcd_add_signal(&vcd_file, + hd44780.irq + IRQ_HD44780_BUSY, + 1 /* bits */, "LCD_BUSY"); + avr_vcd_add_signal(&vcd_file, + hd44780.irq + IRQ_HD44780_ADDR, + 7 /* bits */, "LCD_ADDR"); + avr_vcd_add_signal(&vcd_file, + hd44780.irq + IRQ_HD44780_DATA_IN, + 8 /* bits */, "LCD_DATA_IN"); + avr_vcd_add_signal(&vcd_file, + hd44780.irq + IRQ_HD44780_DATA_OUT, + 8 /* bits */, "LCD_DATA_OUT"); + + avr_vcd_add_signal(&vcd_file, ac_input.irq + IRQ_AC_OUT, 1, "ac_input"); + + avr_vcd_start(&vcd_file); + + printf( "Demo : This is HD44780 LCD demo\n" + " You can configure the width&height of the LCD in the code\n" + " Press 'r' to start recording a 'wave' file - with a LOT of data\n" + " Press 's' to stop recording\n" + ); + + /* + * OpenGL init, can be ignored + */ + glutInit(&argc, argv); /* initialize GLUT system */ + + int w = 5 + hd44780.w * 6; + int h = 5 + hd44780.h * 8; + int pixsize = 3; + + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutInitWindowSize(w * pixsize, h * pixsize); /* width=400pixels height=500pixels */ + window = glutCreateWindow("Press 'q' to quit"); /* create window */ + + initGL(w * pixsize, h * pixsize); + + pthread_t run; + pthread_create(&run, NULL, avr_run_thread, NULL); + + glutMainLoop(); +} diff --git a/examples/board_charlcd/data/blu.tiff b/examples/board_hd77480/data/blu.tiff similarity index 100% rename from examples/board_charlcd/data/blu.tiff rename to examples/board_hd77480/data/blu.tiff diff --git a/examples/board_charlcd/font.tiff b/examples/board_hd77480/data/font.tiff similarity index 100% rename from examples/board_charlcd/font.tiff rename to examples/board_hd77480/data/font.tiff diff --git a/examples/board_charlcd/data/processblu.py b/examples/board_hd77480/data/processblu.py similarity index 100% rename from examples/board_charlcd/data/processblu.py rename to examples/board_hd77480/data/processblu.py diff --git a/examples/board_hd77480/font.h b/examples/board_hd77480/font.h new file mode 100644 index 0000000..7384839 --- /dev/null +++ b/examples/board_hd77480/font.h @@ -0,0 +1,1070 @@ +/* GIMP RGBA C-Source image dump (font.c) */ + +static const struct { + unsigned int width; + unsigned int height; + unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + char *comment; + unsigned char pixel_data[1280 * 7 * 4 + 1]; +} lcd_font = { + 1280, 7, 4, + "generated with gimp from font,tiff", + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0" + "\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377", +}; + diff --git a/examples/parts/ac_input.c b/examples/parts/ac_input.c new file mode 100644 index 0000000..a363f6b --- /dev/null +++ b/examples/parts/ac_input.c @@ -0,0 +1,45 @@ +/* + ac_input.c + + Copyright Luki + Copyright 2011 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#include "sim_avr.h" +#include "ac_input.h" +#include "stdio.h" + +static avr_cycle_count_t +switch_auto(struct avr_t * avr, + avr_cycle_count_t when, void * param) +{ + ac_input_t * b = (ac_input_t *) param; + b->value = !b->value; + avr_raise_irq(b->irq + IRQ_AC_OUT, b->value); + return when + avr_usec_to_cycles(avr, 100000 / 50); +} + +void ac_input_init(struct avr_t *avr, ac_input_t *b) +{ + b->irq = avr_alloc_irq(0, IRQ_AC_COUNT); + b->avr = avr; + b->value = 0; + avr_cycle_timer_register_usec(avr, 100000 / 50, switch_auto, b); + printf("ac_input_init period %duS or %d cycles\n", + 100000 / 50, avr_usec_to_cycles(avr, 100000 / 50)); +} diff --git a/examples/parts/ac_input.h b/examples/parts/ac_input.h new file mode 100644 index 0000000..1a8b3a5 --- /dev/null +++ b/examples/parts/ac_input.h @@ -0,0 +1,49 @@ +/* + ac_input.h + + Copyright Luki + Copyright 2011 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +/* + * Simulates a 50hz changing signal + */ + +#ifndef __AC_INPUT_H__ +#define __AC_INPUT_H__ + +#include "sim_irq.h" + + +enum { + IRQ_AC_OUT = 0, + IRQ_AC_COUNT +}; + +typedef struct ac_input_t { + avr_irq_t * irq; + struct avr_t * avr; + uint8_t value; +} ac_input_t; + +void +ac_input_init( + struct avr_t * avr, + ac_input_t * b); + +#endif diff --git a/examples/parts/hd44780.c b/examples/parts/hd44780.c new file mode 100644 index 0000000..f5ed19b --- /dev/null +++ b/examples/parts/hd44780.c @@ -0,0 +1,374 @@ +/* + hd44780.c + + Copyright Luki + Copyright 2011 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#include +#include +#include +#include "sim_cycle_timers.h" + +#include "hd44780.h" + +void +hd44780_print( + hd44780_t *b) +{ + printf("/******************\\\n"); + const uint8_t offset[] = { 0, 0x40, 0x20, 0x60 }; + for (int i = 0; i < b->h; i++) { + printf("| "); + fwrite(b->vram + offset[i], 1, b->w, stdout); + printf(" |\n"); + } + printf("\\******************/\n"); +} + + +static void +_hd44780_reset_cursor( + hd44780_t *b) +{ + b->cursor = 0; + hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1); + avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor); +} + +static void +_hd44780_clear_screen( + hd44780_t *b) +{ + memset(b->vram, ' ', 80); + hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1); + avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor); +} + + + +/* + * This is called when the delay between operation is triggered + * without the AVR firmware 'reading' the status byte. It + * automatically clears the BUSY flag for the next command + */ +static avr_cycle_count_t +_hd44780_busy_timer( + struct avr_t * avr, + avr_cycle_count_t when, void * param) +{ + hd44780_t *b = (hd44780_t *) param; +// printf("%s called\n", __FUNCTION__); + hd44780_set_flag(b, HD44780_FLAG_BUSY, 0); + avr_raise_irq(b->irq + IRQ_HD44780_BUSY, 0); + return 0; +} + +static void +hd44780_kick_cursor( + hd44780_t *b) +{ + if (hd44780_get_flag(b, HD44780_FLAG_I_D)) { + if (b->cursor < 79) + b->cursor++; + else if (b->cursor < 80+64-1) + b->cursor++; + } else { + if (b->cursor < 80 && b->cursor) + b->cursor--; + else if (b->cursor > 80) + b->cursor--; + hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1); + avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor); + } +} + +/* + * current data byte is ready in b->datapins + */ +static uint32_t +hd44780_write_data( + hd44780_t *b) +{ + uint32_t delay = 37; // uS + b->vram[b->cursor] = b->datapins; + printf("hd44780_write_data %02x\n", b->datapins); + if (hd44780_get_flag(b, HD44780_FLAG_S_C)) { // display shift ? + // TODO display shift + } else { + hd44780_kick_cursor(b); + } + hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1); + return delay; +} + +/* + * current command is ready in b->datapins + */ +static uint32_t +hd44780_write_command( + hd44780_t *b) +{ + uint32_t delay = 37; // uS + int top = 7; // get highest bit set'm + while (top) + if (b->datapins & (1 << top)) + break; + else top--; + printf("hd44780_write_command %02x\n", b->datapins); + + switch (top) { + // Set DDRAM address + case 7: // 1 ADD ADD ADD ADD ADD ADD ADD + b->cursor = b->datapins & 0x7f; + break; + // Set CGRAM address + case 6: // 0 1 ADD ADD ADD ADD ADD ADD ADD + b->cursor = 64 + (b->datapins & 0x3f); + break; + // Function set + case 5: { // 0 0 1 DL N F x x + int four = !hd44780_get_flag(b, HD44780_FLAG_D_L); + hd44780_set_flag(b, HD44780_FLAG_D_L, b->datapins & 16); + hd44780_set_flag(b, HD44780_FLAG_N, b->datapins & 8); + hd44780_set_flag(b, HD44780_FLAG_F, b->datapins & 4); + if (!four && !hd44780_get_flag(b, HD44780_FLAG_D_L)) { + printf("%s activating 4 bits mode\n", __FUNCTION__); + hd44780_set_flag(b, HD44780_FLAG_LOWNIBBLE, 0); + } + } break; + // Cursor display shift + case 4: // 0 0 0 1 S/C R/L x x + hd44780_set_flag(b, HD44780_FLAG_S_C, b->datapins & 8); + hd44780_set_flag(b, HD44780_FLAG_R_L, b->datapins & 4); + break; + // Display on/off control + case 3: // 0 0 0 0 1 D C B + hd44780_set_flag(b, HD44780_FLAG_D, b->datapins & 4); + hd44780_set_flag(b, HD44780_FLAG_C, b->datapins & 2); + hd44780_set_flag(b, HD44780_FLAG_B, b->datapins & 1); + hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1); + break; + // Entry mode set + case 2: // 0 0 0 0 0 1 I/D S + hd44780_set_flag(b, HD44780_FLAG_I_D, b->datapins & 2); + hd44780_set_flag(b, HD44780_FLAG_S, b->datapins & 1); + break; + // Return home + case 1: // 0 0 0 0 0 0 1 x + _hd44780_reset_cursor(b); + delay = 1520; + break; + // Clear display + case 0: // 0 0 0 0 0 0 0 1 + _hd44780_clear_screen(b); + break; + } + return delay; +} + +/* + * the E pin went low, and it's a write + */ +static uint32_t +hd44780_process_write( + hd44780_t *b ) +{ + uint32_t delay = 0; // uS + int four = !hd44780_get_flag(b, HD44780_FLAG_D_L); + int comp = four && hd44780_get_flag(b, HD44780_FLAG_LOWNIBBLE); + int write = 0; + + if (four) { // 4 bits ! + if (comp) + b->datapins = (b->datapins & 0xf0) | ((b->pinstate >> IRQ_HD44780_D4) & 0xf); + else + b->datapins = (b->datapins & 0xf) | ((b->pinstate >> IRQ_HD44780_D4-4) & 0xf0); + write = comp; + b->flags ^= (1 << HD44780_FLAG_LOWNIBBLE); + } else { // 8 bits + b->datapins = (b->pinstate >> IRQ_HD44780_D0) & 0xff; + write++; + } + avr_raise_irq(b->irq + IRQ_HD44780_DATA_IN, b->datapins); + + // write has 8 bits to process + if (write) { + if (hd44780_get_flag(b, HD44780_FLAG_BUSY)) { + printf("%s command %02x write when still BUSY\n", __FUNCTION__, b->datapins); + } + if (b->pinstate & (1 << IRQ_HD44780_RS)) // write data + delay = hd44780_write_data(b); + else // write command + delay = hd44780_write_command(b); + } + return delay; +} + +static uint32_t +hd44780_process_read( + hd44780_t *b ) +{ + uint32_t delay = 0; // uS + int four = !hd44780_get_flag(b, HD44780_FLAG_D_L); + int comp = four && hd44780_get_flag(b, HD44780_FLAG_LOWNIBBLE); + int done = 0; // has something on the datapin we want + + if (comp) { + // ready the 4 final bits on the 'actual' lcd pins + b->readpins <<= 4; + done++; + b->flags ^= (1 << HD44780_FLAG_LOWNIBBLE); + } + + if (!done) { // new read + + if (b->pinstate & (1 << IRQ_HD44780_RS)) { // read data + delay = 37; + b->readpins = b->vram[b->cursor]; + hd44780_kick_cursor(b); + } else { // read 'command' ie status register + delay = 0; // no raising busy when reading busy ! + + // low bits are the current cursor + b->readpins = b->cursor < 80 ? b->cursor : b->cursor-64; + int busy = hd44780_get_flag(b, HD44780_FLAG_BUSY); + b->readpins |= busy ? 0x80 : 0; + + // if (busy) printf("Good boy, guy's reading status byte\n"); + // now that we're read the busy flag, clear it and clear + // the timer too + hd44780_set_flag(b, HD44780_FLAG_BUSY, 0); + avr_raise_irq(b->irq + IRQ_HD44780_BUSY, 0); + avr_cycle_timer_cancel(b->avr, _hd44780_busy_timer, b); + } + avr_raise_irq(b->irq + IRQ_HD44780_DATA_OUT, b->readpins); + + done++; + if (four) + b->flags |= (1 << HD44780_FLAG_LOWNIBBLE); // for next read + } + + // now send the prepared output pins to send as IRQs + if (done) { + avr_raise_irq(b->irq + IRQ_HD44780_ALL, b->readpins >> 4); + for (int i = four ? 4 : 0; i < 8; i++) + avr_raise_irq(b->irq + IRQ_HD44780_D0 + i, (b->readpins >> i) & 1); + } + return delay; +} + +static avr_cycle_count_t +_hd44780_process_e_pinchange( + struct avr_t * avr, + avr_cycle_count_t when, void * param) +{ + hd44780_t *b = (hd44780_t *) param; + + hd44780_set_flag(b, HD44780_FLAG_REENTRANT, 1); + +#if 0 + uint16_t touch = b->oldstate ^ b->pinstate; + printf("LCD: %04x %04x %c %c %c %c\n", b->pinstate, touch, + b->pinstate & (1 << IRQ_HD44780_RW) ? 'R' : 'W', + b->pinstate & (1 << IRQ_HD44780_RS) ? 'D' : 'C', + hd44780_get_flag(b, HD44780_FLAG_LOWNIBBLE) ? 'L' : 'H', + hd44780_get_flag(b, HD44780_FLAG_BUSY) ? 'B' : ' '); +#endif + int delay = 0; // in uS + + if (b->pinstate & (1 << IRQ_HD44780_RW)) // read !?! + delay = hd44780_process_read(b); + else // write + delay = hd44780_process_write(b); + + if (delay) { + hd44780_set_flag(b, HD44780_FLAG_BUSY, 1); + avr_raise_irq(b->irq + IRQ_HD44780_BUSY, 1); + avr_cycle_timer_register_usec(b->avr, delay, + _hd44780_busy_timer, b); + } +// b->oldstate = b->pinstate; + hd44780_set_flag(b, HD44780_FLAG_REENTRANT, 0); + return 0; +} + +static void +hd44780_pin_changed_hook( + struct avr_irq_t * irq, + uint32_t value, + void *param) +{ + hd44780_t *b = (hd44780_t *) param; + + uint16_t old = b->pinstate; + + switch (irq->irq) { + /* + * Update all the pins in one go by calling ourselves + * This is a shortcut for firmware that respects the conventions + */ + case IRQ_HD44780_ALL: + for (int i = 0; i < 4; i++) + hd44780_pin_changed_hook(b->irq + IRQ_HD44780_D4 + i, + ((value >> i) & 1), param); + hd44780_pin_changed_hook(b->irq + IRQ_HD44780_RS, (value >> 4), param); + hd44780_pin_changed_hook(b->irq + IRQ_HD44780_E, (value >> 5), param); + hd44780_pin_changed_hook(b->irq + IRQ_HD44780_RW, (value >> 6), param); + return; // job already done! + case IRQ_HD44780_D0 ... IRQ_HD44780_D7: + // don't update these pins in read mode + if (hd44780_get_flag(b, HD44780_FLAG_REENTRANT)) + return; + break; + } + b->pinstate = (b->pinstate & ~(1 << irq->irq)) | (value << irq->irq); + int eo = old & (1 << IRQ_HD44780_E); + int e = b->pinstate & (1 << IRQ_HD44780_E); + // on the E pin rising edge, do stuff otherwise just exit + if (!eo && e) + avr_cycle_timer_register(b->avr, 1, _hd44780_process_e_pinchange, b); +} + +void +hd44780_init( + struct avr_t *avr, + struct hd44780_t * b, + int width, + int height ) +{ + memset(b, 0, sizeof(*b)); + b->avr = avr; + b->w = width; + b->h = height; + /* + * Register callbacks on all our IRQs + */ + b->irq = avr_alloc_irq(0, IRQ_HD44780_COUNT); + for (int i = 0; i < IRQ_HD44780_INPUT_COUNT; i++) + avr_irq_register_notify(b->irq + i, hd44780_pin_changed_hook, b); + + _hd44780_reset_cursor(b); + _hd44780_clear_screen(b); + + printf("LCD: %duS is %d cycles for your AVR\n", + 37, (int)avr_usec_to_cycles(avr, 37)); + printf("LCD: %duS is %d cycles for your AVR\n", + 1, (int)avr_usec_to_cycles(avr, 1)); +} + diff --git a/examples/parts/hd44780.h b/examples/parts/hd44780.h new file mode 100644 index 0000000..e3f1dd0 --- /dev/null +++ b/examples/parts/hd44780.h @@ -0,0 +1,137 @@ +/* + hd44780.h + + Copyright 2011 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +/* + * This "Part" simulates the business end of a HD44780 LCD display + * It supports from 8x1 to 20x4 or even 40x4 (not sure that exists) + * + * It works both in 4 bits and 8 bits mode and supports a "quicky" method + * of driving that is commonly used on AVR, namely + * (msb) RW:E:RS:D7:D6:D5:D4 (lsb) + * + * + As usual, the "RW" pin is optional if you are willing to wait for the + * specific number of cycles as per the datasheet (37uS between operations) + * + If you decide to use the RW pin, the "busy" flag is supported and will + * be automaticly cleared on the second read, to exercisee the code a bit. + * + Cursor is supported, but now "display shift" + * + The Character RAM is supported, but is not currently drawn. + * + * To interface this part, you can use the "INPUT" IRQs and hook them to the + * simavr instance, if you use the RW pins or read back frim the display, you + * can hook the data pins /back/ to the AVR too. + * + * The "part" also provides various IRQs that are there to be placed in a VCD file + * to show what is sent, and some of the internal status. + * + * This part has been tested with two different implementation of an AVR driver + * for the hd44780. The one shipped in this directory is straight out of the + * avr-libc example code. + */ +#ifndef __HD44780_H__ +#define __HD44780_H__ + +#include "sim_irq.h" + +enum { + IRQ_HD44780_ALL = 0, // Only if (msb) RW:E:RS:D7:D6:D5:D4 (lsb) configured + IRQ_HD44780_RS, + IRQ_HD44780_RW, + IRQ_HD44780_E, + // bidirectional + IRQ_HD44780_D0,IRQ_HD44780_D1,IRQ_HD44780_D2,IRQ_HD44780_D3, + IRQ_HD44780_D4,IRQ_HD44780_D5,IRQ_HD44780_D6,IRQ_HD44780_D7, + IRQ_HD44780_INPUT_COUNT, + + IRQ_HD44780_BUSY, // for VCD traces sake... + IRQ_HD44780_ADDR, + IRQ_HD44780_DATA_IN, + IRQ_HD44780_DATA_OUT, + IRQ_HD44780_COUNT +}; + +enum { + HD44780_FLAG_F = 0, // 1: 5x10 Font, 0: 5x7 Font + HD44780_FLAG_N, // 1: 2/4-lines Display, 0: 1-line Display, + HD44780_FLAG_D_L, // 1: 4-Bit Interface, 0: 8-Bit Interface + HD44780_FLAG_R_L, // 1: Shift right, 0: shift left + HD44780_FLAG_S_C, // 1: Display shift, 0: Cursor move + HD44780_FLAG_B, // 1: Cursor Blink + HD44780_FLAG_C, // 1: Cursor on + HD44780_FLAG_D, // 1: Set Entire Display memory (for clear) + HD44780_FLAG_S, // 1: Follow display shift + HD44780_FLAG_I_D, // 1: Increment, 0: Decrement + + /* + * Internal flags, not HD44780 + */ + HD44780_FLAG_LOWNIBBLE, // 1: 4 bits mode, write/read low nibble + HD44780_FLAG_BUSY, // 1: Busy between instruction, 0: ready + HD44780_FLAG_REENTRANT, // 1: Do not update pins + + HD44780_FLAG_DIRTY, // 1: needs redisplay... + HD44780_FLAG_CRAM_DIRTY, // 1: Character memory has changed +}; + + +typedef struct hd44780_t +{ + avr_irq_t * irq; + struct avr_t * avr; + int w, h; // width and height of the LCD + + uint16_t cursor; // offset in vram + uint8_t vram[80 + 64]; + + uint16_t pinstate; // 'actual' LCd data pins (IRQ bit field) + // uint16_t oldstate; /// previous pins + uint8_t datapins; // composite of 4 high bits, or 8 bits + uint8_t readpins; + + uint16_t flags; // LCD flags ( HD44780_FLAG_*) +} hd44780_t; + +void +hd44780_init( + struct avr_t *avr, + struct hd44780_t * b, + int width, + int height ); +void +hd44780_print( + struct hd44780_t *b); + +static inline int +hd44780_set_flag( + hd44780_t *b, uint16_t bit, int val) +{ + int old = b->flags & (1 << bit); + b->flags = (b->flags & ~(1 << bit)) | (val ? (1 << bit) : 0); + return old != 0; +} + +static inline int +hd44780_get_flag( + hd44780_t *b, uint16_t bit) +{ + return (b->flags & (1 << bit)) != 0; +} + +#endif diff --git a/examples/parts/hd44780_glut.c b/examples/parts/hd44780_glut.c new file mode 100644 index 0000000..56940f5 --- /dev/null +++ b/examples/parts/hd44780_glut.c @@ -0,0 +1,151 @@ +/* + hd44780_glut.c + + Copyright Luki + Copyright 2011 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#include "hd44780_glut.h" + +#include +#include + +#include "font.h" // generated with gimp + +static GLuint font_texture; +static int charwidth = 5; +static int charheight = 7; + +void +hd44780_gl_init() +{ + glGenTextures(1, &font_texture); + glBindTexture(GL_TEXTURE_2D, font_texture); + glTexImage2D(GL_TEXTURE_2D, 0, 4, + lcd_font.width, + lcd_font.height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, + lcd_font.pixel_data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glScalef(1.0f / (GLfloat) lcd_font.width, 1.0f / (GLfloat) lcd_font.height, 1.0f); + + glMatrixMode(GL_MODELVIEW); +} + +static inline void +glColor32U(uint32_t color) +{ + glColor4f( + (float)((color >> 24) & 0xff) / 255.0f, + (float)((color >> 16) & 0xff) / 255.0f, + (float)((color >> 8) & 0xff) / 255.0f, + (float)((color) & 0xff) / 255.0f ); +} + +void +glputchar(char c, + uint32_t character, + uint32_t text, + uint32_t shadow) +{ + int index = c; + int left = index * charwidth; + int right = index * charwidth + charwidth; + int top = 0; + int bottom = 7; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable(GL_TEXTURE_2D); + glColor32U(character); + glBegin(GL_QUADS); + glVertex3i(5, 7, 0); + glVertex3i(0, 7, 0); + glVertex3i(0, 0, 0); + glVertex3i(5, 0, 0); + glEnd(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, font_texture); + if (shadow) { + glColor32U(shadow); + glPushMatrix(); + glTranslatef(.2f, .2f, 0); + glBegin(GL_QUADS); + glTexCoord2i(right, top); glVertex3i(5, 0, 0); + glTexCoord2i(left, top); glVertex3i(0, 0, 0); + glTexCoord2i(left, bottom); glVertex3i(0, 7, 0); + glTexCoord2i(right, bottom); glVertex3i(5, 7, 0); + glEnd(); + glPopMatrix(); + } + glColor32U(text); + glBegin(GL_QUADS); + glTexCoord2i(right, top); glVertex3i(5, 0, 0); + glTexCoord2i(left, top); glVertex3i(0, 0, 0); + glTexCoord2i(left, bottom); glVertex3i(0, 7, 0); + glTexCoord2i(right, bottom); glVertex3i(5, 7, 0); + glEnd(); + +} + +void +hd44780_gl_draw( + hd44780_t *b, + uint32_t background, + uint32_t character, + uint32_t text, + uint32_t shadow) +{ + int rows = b->w; + int lines = b->h; + int border = 3; + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glColor32U(background); + glTranslatef(border, border, 0); + glBegin(GL_QUADS); + glVertex3f(rows * charwidth + (rows - 1) + border, -border, 0); + glVertex3f(-border, -border, 0); + glVertex3f(-border, lines * charheight + (lines - 1) + border, 0); + glVertex3f(rows * charwidth + (rows - 1) + border, lines * charheight + + (lines - 1) + border, 0); + glEnd(); + + glColor3f(1.0f, 1.0f, 1.0f); + const uint8_t offset[] = { 0, 0x40, 0x20, 0x60 }; + for (int v = 0 ; v < b->h; v++) { + glPushMatrix(); + for (int i = 0; i < b->w; i++) { + glputchar(b->vram[offset[v] + i], character, text, shadow); + glTranslatef(6, 0, 0); + } + glPopMatrix(); + glTranslatef(0, 8, 0); + } + hd44780_set_flag(b, HD44780_FLAG_DIRTY, 0); +} diff --git a/examples/parts/hd44780_glut.h b/examples/parts/hd44780_glut.h new file mode 100644 index 0000000..15b8717 --- /dev/null +++ b/examples/parts/hd44780_glut.h @@ -0,0 +1,38 @@ +/* + hd44780_glut.h + + Copyright Luki + Copyright 2011 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ +#ifndef __HD44780_GLUT_H__ +#define __HD44780_GLUT_H__ + +#include "hd44780.h" + +void +hd44780_gl_draw( + hd44780_t *b, + uint32_t background, + uint32_t character, + uint32_t text, + uint32_t shadow); + +void +hd44780_gl_init(); + +#endif -- 2.39.5