Menu

Code complies okay yet to create a hex file "symbol 40.0 has not been defined" is an error. Why?

Ray Palmer
2018-09-09
2018-09-09
  • Ray Palmer

    Ray Palmer - 2018-09-09

    Hello everyone,

    I am new to GCB (as in just started using it over thse last 6 months).

    The compiler I am using is v98 (Installed Aug 18 on WIn 7 64bit).
    The code compiles with no errors, yet when I want to make a "hex" file the process returns an error.

    The Error is:

    Error: GCASM: Symbol 40.0 has not been defined

    Why or more importantly how can this be solved.

    It still creates a hex file and when i have looked at the ".lst" file it does not list any errors in the assembly, so what gives? I have assumed the hex file is just a by-prodcut of the process and cannot be sure it is okay to use as is.

    The code is for the PIC 18F4550 to initially handle a PS/2 keyboard or mouse input and re-map it to my old 1985 computer (AMSTRAD CPC6128).

    The code is:

    '===============================================================
    '
    '  Purpose: To handle a PS/2 key board or mouse connected to a
    '           PIC chip which can read in the PS/2 code sequence
    '           and then decode it to the equivalent CPC scanline
    '           code. The Mapping will take what the user types in
    '           as seen on the PS/2 keyboard and correct it for the
    '           CPC equivalent.
    '
    '           This program does map not key for key, rather to get
    '           the same user expectation when a PS/2 key pressed.
    '           For example shift 2 on PS/2 is an '@' but on the
    '           CPC its a " so the "@" is mapped to the cpc
    '           scanline which would be used for CPC keyboard
    '           equivalent. The benefit to this mode of operation is
    '           that the user is not going to see an unexpected key
    '           displayed for what is shown on the actual PS/2
    '           keyboard. The exception to this is the pound symbol
    '           which is not shown on a standard PS/2 keyboard, but
    '           is on the CPC. The pound symbol is accessed via the
    '           shift ` (Shift back tick, above TAB key).
    '
    '           The keymapping is the default QWERTY keyboard and
    '           the use of an unused keys may be expanded to select
    '           AZERTY or QWERTY keyboard.
    '
    '===============================================================
    #option explicit
    '
    #chip PIC18F4550,20
    '
    #define CONF_WORD = 0x3f3a
    #define CLOCK_FREQUENCY = 20
    #define SIMULATION_WAITMS_VALUE = 0
    '
    ' Define Ports direction to use
    '
    #option Volatile PortA.7
    #option Volatile PortA.6
    '
    DIR PORTA In        'PS/2 keyboard/Mouse to PIC
                        'PIC to Host key scan line request.
                        'CPC to PIC scan line request
    '
    DIR PORTB Out       'PIC to CPC scan line code response
    '
    '  hardware defined lines in schematic
    '
    #define cpc_scan = PORTA       'Bits 0 to 3 for CPC scan line request
    #define cpc_output = PORTB     'defines our output scan data port
    '
    #define ps2_kdata = PORTA.7   'ps/2 keyboard data pin
    #define ps2_kclock = PORTA.6  'ps/2 keyboard clock pin
    #define ps2_mdata = PORTA.4   'ps/2 mouse data pin
    #define ps2_mclock = PORTA.5  'PS/2 mouse clock pin
    '
    #define PS2_CTRLKEY = 0x14
    #define PS2_LEFTSHIFT = 0x12
    #define PS2_RIGHTSHIFT = 0x59
    #define PS2_CAPSLOCK = 0x58
    '===============================================================
    ' Variables Declarations
    '===============================================================
    Dim reg_w As word
    Dim reg_status As Byte
    '
    ' PS/2 control/shift/caps lock key flags
    '
    Dim ps2_shift As Bit
    Dim ps2_caps As Bit
    Dim ps2_ctrl As Bit
    '
    Dim ps2_keyup as Bit              'Detection of key up/down
    Dim ps2_doublecode As Bit
    '
    ' data to/from PS/2 device
    '
    Dim ps2_k_data As Byte
    Dim ps2_m_data as byte
    '
    '  PS/2 I/O processing flags
    '
    Dim ps2_kreading As Bit
    Dim ps2_kwriting As Bit
    Dim ps2_kreaddone As Bit
    Dim ps2_kparity As Bit
    Dim ps2_kbitcount As Byte
    '
    Dim ps2_mreaddone As Bit
    Dim ps2_mreading As Bit
    Dim ps2_mparity As Bit
    Dim ps2_mbitcount As Byte
    Dim ps2_mousedat(4) as Byte
    Dim ps2_mdidx as Byte
    '
    '  cpc key mapping flags/variables
    '
    Dim senddata2cpc as Bit
    Dim cpc_keyscan as Byte           'Output from 8255 (lower nibble)
    Dim cpc_prevks as Byte
    Dim cpc_caps as bit
    Dim cpc_yline(17) as byte         'output for each scan line
    Dim ti as Byte
    Dim yi as byte
    Dim xi as byte
    Dim si as Byte
    Dim cpc_rowcol as byte
    Dim bit_mask(9) as Byte
    Dim IntProcFlag as Bit
    '===============================================================
    '
    '  PS/2 keyboard scan codes.
    '  Format of each byte is:
    '   cpc row value in upper
    '   cpc column in lower
    '
    '  Index is the PS/2 key code.
    '
    '  Scancodes in these tables are for the US keyboard layout.
    '
    '===============================================================
    Table cpc_qwerty_kb
    '
    ' unshifted codes (128 byte, index of 0 to 127)
    '
    255,255,255,255,255,255,255,255,255,255,255,255,255,149, 55,255
    255, 34, 54,255, 56,148,145,255,255,255,152,119,150,132,146,255
    255,135,136,134,131,129,130,255,255,104,120,118,116,115,114,255
    255,103,119,101,117,100,113,255,255,255, 87,102, 99, 98, 97,255
    255, 88, 86, 84, 83, 81, 82,255,255, 72, 71, 67, 69, 68, 80,255
    255,255,146,255, 50, 69,255,255,151, 54, 23, 52,255,255,255,255
    255,255,255,255,255,255,168,255,255, 38,255, 53,255,255,255,255
     40, 24, 39, 37, 21, 36,147,255,255, 69, 22, 66, 70, 20,255,255
    '
    ' shifted codes (128 bytes, index of 128 to 255)
    '
    255,255,255,255,255,255,255,255,255,255,255,255,255,149, 65,255
    255, 34, 54,255, 56,148,145,255,255,255,152,119,150,132, 67,255
    255,135,136,134,131,129,130,255,255,104,120,118,116,115,114,255
    255,103,119,101,117,100, 65,255,255,255, 87,102, 99,113, 70,255
    255, 88, 86, 84, 83, 82, 97,255,255, 72, 71, 67, 70, 68, 66,255
    255,255, 55,255, 50, 66,255,255,151, 54, 23, 52,255,255,255,255
    255,255,255,255,255,255,168,255,255, 38,255, 53,255,255,255,255
     40, 24, 39, 37, 21, 36,147,255,255, 69, 22, 66, 70, 20,255,255
    '
    End Table
    '======================================================================
    '  Start of executable of PIC Chip
    '======================================================================
    bit_mask = 1, 2, 4, 8, 16, 32, 64, 128
    cpc_yline = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    '
    ps2_mdidx = 1
    ps2_mreaddone = 0
    '
    ps2_kreaddone = 0
    ps2_kwriting = 0
    '
    ps2_caps = 0            'No caps lock
    ps2_shift = 0           'no left or right shift key pressed
    ps2_ctrl = 0            'no left/right control key pressed
    '
    'OPTION_REG.INTEDG = 0
    INTCON2 = 0x70          'triggers interrupts on falling edge
    INTCON.INT0E = 1        'enables RB0 Interrupt for ps/2
    INTCON.GIE = 1          'enable all interrupts
    IntProcFlag = 0
    '
    On Interrupt PORTChange call MyIntHandler 'HandleInt
    '
    ps2_kclock = ps2_kclock 'Trigger interupt
    ps2_mclock = ps2_mclock 'Trigger interupt
    '
    Wait 1000 ms            'pauses 1 second for PS/2 I/O To settle
    '
    IntProcFlag = 1
    '
    loop:
      '=================================================================
      '
      ' Answering scanline requests from CPC to determine which key
      ' the cpc thinks was pressed.
      '
      ' Scanline requests 0 to 9 are for keyboard
      ' Scanline requests 10 to 15 are for joystick
      '
      '=================================================================
      cpc_keyscan = cpc_scan                   'get CPC scan request
      '
      if cpc_prevks <> cpc_keyscan then
        '
        ' New scanline request
        '
        cpc_prevks = cpc_keyscan
        cpc_keyscan = (cpc_keyscan AND 15) + 1 'Calc index into array
        cpc_output = !cpc_yline(cpc_keyscan)   'Send data to CPC
        cpc_yline(cpc_keyscan) = 0
        '
        if ps2_caps then
          cpc_yline(9) = cpc_yline(9) OR bit_mask(7)  'Bit 6
        end if
        '
        if ps2_shift then
          cpc_yline(3) = cpc_yline(3) OR bit_mask(6)  'Bit 5
        end if
        '
        if ps2_ctrl then
          cpc_yline(3) = cpc_yline(3) OR bit_mask(8)  'Bit 7
        end if
        '
      end if
      '=================================================================
      '
      ' Check if PS/2 device data has been read in
      '
      '=================================================================
      If ps2_kreaddone Then
        '
        ' Have now completed reading PS/2 keyboard code sequence
        ' Lets now convert to AMSTRAD CPC scanline code
        '
        ' ps2_k_data = PS/2 keycode for the key pressed (7 bit)
        ' ps2_keyup  = 0 key has been pressed.
        '              1 key released.
        '
        if ps2_k_data = PS2_CAPSLOCK and not ps2_keyup Then
          '
          ' CAPS lock has been pressed (toggle state)
          '
          ps2_caps = not cpc_caps
          ps2_keyup = 1 'skip any processing with this key
        end if
        '
        if ps2_k_data = PS2_CTRLKEY Then
          '
          ' Setup Ctrl flag if pressed or released
          '
          ps2_ctrl = not ps2_keyup
        end if
        '
        if ps2_k_data = PS2_LEFTSHIFT or ps2_k_data = PS2_RIGHTSHIFT Then
          '
          ' Setup shift flag via PS/2 left or right shift key detection
          '
          ps2_shift = not ps2_keyup
          ps2_k_data = ps2_k_data + 128 'index to shifted codes
        end if
        '==================================================================
        '
        ' Search for which CPC equivalent to become active
        '
        '==================================================================
        if !ps2_keyup then
          '
          ' A key has been pressed
          '
          ps2_keyup  = 1
          if ps2_doublecode then
            '
            cpc_rowcol = 255
            if ps2_k_data = 17 then
              cpc_rowcol = 34  'copy key
            end if
            if ps2_k_data = 20 then
              cpc_rowcol = 56  'Control key
            end if
            if ps2_k_data = 90 then
              cpc_rowcol = 23  'Keypad Enter
            end if
            if ps2_k_data = 107 then
              cpc_rowcol = 33 'Cursor left
            end if
            if ps2_k_data = 113 then
              cpc_rowcol = 49 'Clear Key
            end if
            if ps2_k_data = 114 then
              cpc_rowcol = 19 'Cursor Down
            end if
            if ps2_k_data = 116 then
              cpc_rowcol = 18 'Cursor Right
            end if
            if ps2_k_data = 117 then
              cpc_rowcol = 17 'Cursor Up
            end if
            '
          else
              ReadTable cpc_qwerty_kb, ps2_k_data, cpc_rowcol
          end if
          '
          if cpc_rowcol <> 255 Then
            '
            ' Assume row is not greater than 10
            ' Assume row is not greater then 8
            '
            yi = cpc_rowcol/16      'Calculate row
            xi = cpc_rowcol - yi*16 'Calculate column
            '
            cpc_yline(yi) = cpc_yline(yi) OR bit_mask(xi)
          end if
        end if
      end if
      '
    exitforloop:
      '
      '=================================================================
      '
      ' Check mouse inputs
      '
      '=================================================================
      if ps2_mreaddone Then
        '
        ' Data from PS/2 mouse now read in, so lets handle it now
        '
        ' PS/2 mouse data format is:
        '          bit 7  6  5  4  3  2  1  0
        '  Byte 1      YO XO YS XS 1  MB RB LB
        '       2      --------X Movement-----
        '       3      --------Y Movement-----
        '
        '  YO = Y overflow (1 = means movement > 255)
        '  XO = X overflow (1 = means movement > 255)
        '  YS = Y direction sign (0 = Up, 1 = Down)
        '  XS = X direction sign (0 = Right, 1 = Left)
        '  MB = Middle button (1 = Pressed, 0 = not pressed)
        '  RB = Right button (1 = Pressed, 0 = not pressed)
        '  LB = Left button (1 = Pressed, 0 = not pressed)
        '
        yi = 16              'Mouse acts like Joystick to CPC
        '
        if cpc_yline(yi) = 0 then
          '
          ' CPC is free to get mouse input
          '
          if ps2_mousedat(3) <> 0 then
            '
            ' Mouse has moved up or down
            '
            if ps2_mousedat(1).5 Then
              '
              ' Mouse has moved Down (Set Bit 1)
              '
              xi = 2  ' bit 1
            Else
              '
              ' Mouse has moved Up (Set Bit 0)
              '
              xi = 1  ' bit 0
            end if
            '
            cpc_yline(yi) = cpc_yline(yi) OR bit_mask(xi)
          end if
          '
          if ps2_mousedat(2) <> 0 then
            '
            ' Mouse has moved left or right
            '
            if ps2_mousedat(1).4 Then
              '
              ' Mouse has moved Left (Set Bit 2)
              '
              xi = 3  ' bit 2
            Else
              '
              ' Mouse has moved Right (Set Bit 3)
              '
              xi = 4  ' bit 3
            end if
            '
            cpc_yline(yi) = cpc_yline(yi) OR bit_mask(xi)
          end if
          '
          if ps2_mousedat(1).1 Then
            '
            ' Mouse has right button depressed
            ' Assign this to Fire 1 (Bit 4)
            '
            cpc_yline(yi) = cpc_yline(yi) OR bit_mask(5)  ' bit 4
          end if
          '
          if ps2_mousedat(1).0 Then
            '
            ' Mouse has left button depressed
            ' Assign this to Fire 2 (Bit 5)
            '
            cpc_yline(yi) = cpc_yline(yi) OR bit_mask(6)  ' bit 5
          end if
          '
          if ps2_mousedat(1).2 Then
            '
            ' Mouse has middle button depressed
            ' Assign the action to 'spare' line of joystick (Bit 6)
            '
            cpc_yline(yi) = cpc_yline(yi) OR bit_mask(7)  ' bit 6
          end if
          '
        end if
      end if
      '
      ps2_mreaddone = 0
      ps2_kreaddone = 0
      ps2_mreading = 1  ' flag read another mouse sequence
      ps2_kreading = 1  ' flag read another keyboard sequence
      ps2_keyup = 1
      '
      Goto loop
      '
    End
    '
    Sub MyIntHandler  'HandleInt
      '
      ' handle interrupts on PORT A to get/send PS/2 Data (KB/Mouse).
      '
      if IntProcFlag = 0 Then
        '
        ' Flag now processing this interrupt (prevent another interrupt
        ' interfering with this one).
        '
        IntProcFlag = 1         'Prevent re-enter while handing current
        '
        reg_status = STATUS     'preserve status
        reg_w = WREG            'preserve WREG
        '
        '=================================================================
        '
        If ps2_kreading Then
          '
          if not ps2_kclock then
            '
            ' Keyboard to PIC transmission (PS/2 Keyboard clock is low)
            '
            ' Code does not handle PAUSE and PRNT SCRN keys (dont use them!)
            '
            if ps2_kbitcount <> 0 then
              '
              if ps2_kbitcount < 9 then
                '
                ps2_k_data = FnLSR(ps2_k_data,1)
                ps2_k_data.7 = ps2_kdata
                ps2_kparity = ps2_k_data Xor ps2_kparity
              end if
            else
              '
              ' first bit got, so more to get
              '
              ps2_kreaddone = 0
              ps2_kparity = 0
              ps2_k_data = 0
            end if
            '
            ps2_kbitcount = ps2_kbitcount + 1
            '
            if ps2_kbitcount = 11 then
              '
              ' All data for this byte got.
              '
              ps2_kbitcount = 0
              '
              ' Check if the sequence is a double code sequence
              '
              if ps2_k_data = 0xE0 then
                ps2_doublecode = 1    'flag double byte sequence
              Else
                ps2_doublecode = 0    'flag sequence is 1 Byte
              end if
              '
              ' Check if the sequence is a break sequence
              '
    
              if ps2_k_data = 0xF0 then
                ps2_keyup = 1       'flag non-break sequence
              Else
                ps2_keyup = 0       'flag break sequence
              end if
              '
              if ps2_k_data <> 0xE0 AND ps2_k_data <> 0xF0 then
                '
                ' The current data from the PS/2 is now completed
                ' the code sequence
                '
                ps2_kreaddone = 1
              end if
              '
            end if
          end if
        end if
        '
        '=================================================================
        '
        if ps2_mreading Then
          '
          if not ps2_mclock then
            '
            ' Mouse to PIC transmission (PS/2 Mouse Clock is low)
            '
            if ps2_mbitcount <> 0 then
              '
              if ps2_mbitcount < 9 then
                '
                ps2_m_data = FnLSR(ps2_m_data,1)
                ps2_m_data.7 = ps2_mdata
                ps2_mparity = ps2_m_data Xor ps2_mparity
              end if
              '
            else
              '
              ' first bit got, so more to get
              '
              ps2_mreaddone = 0
              ps2_mdidx = 0
              ps2_m_data = 0
              ps2_mparity = 0
            end if
            '
            ps2_mbitcount = ps2_mbitcount + 1
            '
            if ps2_mbitcount = 11 then
              '
              ' All data for this byte got.
              '
              ps2_mbitcount = 0
              ps2_mdidx = ps2_mdidx + 1
              ps2_mousedat(ps2_mdidx) = ps2_m_data
              if ps2_mdidx = 3 Then
                '
                ' Saved 3 bytes of mouse data so code
                ' sequence is now complete
                '
                ps2_mreaddone = 1
              end if
            end if
          end if
        end if
        '
        '=================================================================
        '
    exit_int_sub:
        STATUS = reg_status
        WREG = reg_w
    
        IntProcFlag = 0
      end if
    end sub
    
     
  • Anobium

    Anobium - 2018-09-09

    @Ray

    The issue is caused by the XOR statement when you are XOR a bit and a byte. Line 439

    ~~~
    dim myTemp as bit
    myTemp = ps2_k_data.7 Xor ps2_kparity 'is this the correct bits??? I do not know.
    ps2_kparity = myTemp
    ~~~

    I suspect that 'ps2_mparity = ps2_m_data Xor ps2_mparity' will also require changing.

    Please use the workaround above but we will look at resolving asap.

    Anobium

    PS: As a newbee your coding style is excellent. As I was able to isolate this issue in a few moments.
    - You should not need the STATUS and WREG handlers we that is automatic in Great Cow BASIC.
    - You may want to change the label loop: to a DO - LOOP, to remove the GOTO loop. I was surprised this compiled with the use of a reserved word as a label. :-)

    Nice program - sorry for the issue in the generated ASM.

     

    Last edit: Anobium 2018-09-09
  • Ray Palmer

    Ray Palmer - 2018-09-09

    Anobium,

    Thanks for the advice. It does now work with out the error.

    The DO...LOOP is something I should have used for proper software coding (i have been a programmer since my uni days, like 30+ years ago).

    The code i change to is:

    tmpbit = ps2_kdata Xor ps2_kparity
    ps2_kparity = tmpbit

    I also realised that ps2_k_data should have been ps2_kdata (was a fat finger problem).

    Rap Palmer

     

Log in to post a comment.