• Keyboard Controller with Joystick for MSX (2)

    11/26/2022 at 21:33 0 comments

    Added a second diode to enhance the detection

    And drafted some driver code that provides scan and decode that takes 98 bytes plus 5 RAM addresses.

    ; Scan Atari keyboard and single button joystick using 
    ; and adapter with 74LS139
    
    ; PSG IO addresses
    PSGAD: EQU 0A0H
    PSGWR: EQU 0A1H
    PSGRD: EQU 0A2H
    
    ; DetectKB2600 - Detect Atari controller keyboard
    ; Input: 
    ;       register A: 0=Connector 1, >0=Connector 2.
    ; Ouptut:
    ;       Z -> keyboard detected
    ;      NZ -> keyboard adapter not detected
    DetectKB2600:
      call ScanKB2600
      ld de,KBROWS
      ld c,0
    Detct0:
      ld a,(de)
      and 00010000b ; isolate bit 4
      rla
      or c
      ld c,a
      inc de
    djnz Detct0
      cp 01000000b
      ret
    
    ;
    ; ScanKB2600 - Scan Atari controller keyboard 
    ;
    ; Inputs: 
    ;        register A: 0=Connector 1, >0=Connector 2.
    ; Ouptuts   :          bit  7  6  5  4  3  2  1  0
    ;           KBROWS     ->   1  1  1  0  #  9  6  3
    ;           KBROWS + 1 ->   1  1  1  1  0  8  5  2
    ;           KBROWS + 2 ->   1  1  1  0  *  7  4  1
    ;(JOYTBITS) KBROWS + 3 ->   1  1  1  TA RG LF DW UP
    
    ScanKB2600:  
       ; set zero flag according to port option
       and a
       ; Save PSG Context
       ld a,15
       out (PSGAD),a
       in a,(PSGRD)
       ld (SAVPSG),a
       ld hl, KBROWS
    
       ; Select Joystick port accordingly
       jr NZ, ScanCon2
       
    ScanCon1:
       and 10101101b  ; clear bit 6 -> Joysel -> joy port 0, 4:PULSE and 1:TRIGGER B
    ;  a = pins 8,7 low  (row 0)
       ld b,a  ; a = pin 8=0, pin 7=0 (row 0)
       set 4,b ; b = pin 8=1, pin 7=0 (row 1)
       ld c,b  ;
       set 1,c ; c = pin 8=1, pin 7=1 (row 2)
       ld d,a  ; a = pin 8=0, pin 7=0 (row 0)
       set 1,d ; b = pin 8=0, pin 7=1 (Joystick)
    
       jr ScanRow0
    
    ScanCon2:
    
       and 10010111b  ; clear bit 5:PULSE and 3:TRIGGER B
       set 6,a        ; Set bit 6 -> Joysel -> joy port 1
       ld b,a  ; a = pin 8=0, pin 7=0 (row 0)
       set 5,b ; b = pin 8=1, pin 7=0 (row 1)
       ld c,b  ;
       set 3,c ; c = pin 8=1, pin 7=1 (row 2)
       ld d,a  ; a = pin 8=0, pin 7=0 (row 0)
       set 3,d ; b = pin 8=0, pin 7=1 (Joystick)
    
    ScanRow0:
       ld e,a
       call SaveRow
    
    ScanRow1:  
       ld e,b
       call SaveRow
    
    ScanRow2:  
       ld e,c
       call SaveRow
       
    ScanJoy:
       ld e,d
       call SaveRow
    
    RestorePSG:
       ld e,(hl) ; hl now points to SAVPSG
       
    SaveRow:
       di             ; disable interrupts
       ld a,15
       out (PSGAD),a
       ld a, e
       out (PSGWR),a  ; update register 15
       ld a,14
       out (PSGAD),a  ; select register 14
       in a,(PSGRD)   ; read keys hhhh*741
       or 11110000b   ; mask unused bits
       ld (HL),a      ; save keyboard state
       inc hl
       ei
       ret
    
     ; Variables
    ; keyboard rows HHHL#963, HHHH0852, HHHL*741
     KBROWS:  DS 3
     JOYBITS: DS 1
    ;   PSG register 15 save state during execution, destroyed buttons at the end
    ; must be contiguous to Joybits
     SAVPSG: DS 1 

  • Keyboard Controller with Joystick for MSX

    11/19/2022 at 10:49 0 comments

    I have built the Atari 2600 controller keyboard DIY to develop an adapter and write a driver for MSX. The adapter aimed for simplicity but it does not provide any detection feature, requiring the user to without an action, either pressing a key or move the joystick to any direction, depending upon the peripheral connected on the joystick port.

    If I give up the simplicity and add an Integrated Circuit and a bunch of diodes it is possible, though, to build an adapter that can support both the keyboard controller and a single button joystick, connected at the same time, using basically the same driver. And there's more: the joystick can still be read by Basic.

    here's the circuit:

    The rows of the keyboard connected at X2 are selected by the pins PULSE (8) and TRIGGER_B(7) (which is bidirectional). The default state of these pins are PULSE->0 and TRIGGER_B->1 which selects the common line of the joystick, thus allowing the single button joystick connected to X3 to be read using BASIC.

    Detection is possible by Selecting the third keyboard ROW, then diode D5 will bring down the level on the TRIGGER_A line. The other keyboard rows will keep this line high.

  • Patching Muhonmourn 3 (2)

    11/15/2022 at 03:12 0 comments

    Making a Cartridge version of the game

    I have created a ROM version of Muhonmourn3. It was necessary to move the game to RAM because the game uses contiguous areas to store data (and some areas beyond 0xd400 too).

    Additionally, it was required another routine to switch back page 1 from the Game ROM slot to the same slot of the BIOS, otherwise the game ran erratically (slowed down and missing time counter and player counters).

    The ROM -> RAM loader is very primitive but it seems to be working fine in many emulated machines.

    The loader executes the following steps:

    1. Check if the computer has enough RAM to load the game
    2. Load a Splash Screen (or a NO RAM screen advice)
    3. Copy patch code (from page 1) to RAM segment E000-E1F0
    4. Copy game code (from page 1) to RAM segment c000-d400
    5. Copy game code (from page 2) to RAM segment 8000-bfff using RDSLT
    6. copy page switch code (from page 1) to RAM segment E1F0
    7. switch page 1 to the same slot that is BIOS ROM
    8. Jump to game start at RAM 0x915f

    The patch was modified to change the text on the screen accordingly with the Ninja Tap presence:

    The whole repository can be found at my github page, and here's the link for downloading the ROM image.

    Splash Screen

    The ROM loader adds about 2 seconds to the startup of the machine running the game, then a Splash screen was added to divert the attention and reduce the perception of the loading time.

    The Splash screen uses Screen 3 multi-color mode, with a resolution of 64 x 48 pixels. The image was edited using mspaint and the space color was reduced to 16 colors indexed mode (bitmap) using irfanview, then a python script to convert the pixel information into data to be included on the loader code. 

    The screen 3 mode uses 1 byte to represent the color of two pixels (each nibble is a pixel color). The whole screen takes 1536 bytes which is the half of 64 x 48 -> 3072 pixels available.

    The pixel addressing is not linear but with a bit of observation it is possible to assign the values of the coordinates X and Y to certain bits on a linear addressing word:

    def getCoords ( linearCount ):
        # bit order   Y5 Y4 Y3 X5 - X4 X3 X2 X1 .Y2 Y1 Y0 X0
        #        x    0  0  0  1    1  1  1  1   0  0  0  1
        #        y    1  1  1  0    0  0  0  0   1  1  1  0
        cx = ( (linearCount & 0x1f0)  >> 3) + (  linearCount & 0x01 )
        cy = ( (linearCount & 0xe00) >> 6) + ( (linearCount & 0x0e) >> 1)
        return cx,cy


    The color translation was done kinda manually, assigning the the indexes informed by clicking on the image opened on Irfanview  to the desired MSX color.

    def translateColor (inputColor):
        #msxCores = [ 1, 3, 7, 9, 11, 14, 15]
        msxCores = [ 1, 3, 7, 15, 6, 14, 9]
        if inputColor <= len(msxCores):
            return msxCores [ inputColor ]
        else:
            return 1

     The main function iterates over all 3072 pixels, combining every 2 of them and generating the contents for a include file, skipping a line every 32 pixels (16 bytes).

    for i in range (0,1536*2,2):
        x,y = getCoords (i)
        pp = translateColor ( pixels [x,y] )  # get MSB color
        x,y = getCoords (i+1)
        ss = translateColor ( pixels [x,y] )  # get LSB color
        bb = (pp<<4 | ss ) & 0xff
    
        if (i % 32 == 0 ):
            outputBuffer = outputBuffer + "\n db "
        else:
            outputBuffer = outputBuffer + ', '
        outputBuffer = outputBuffer + intToHexValue2digits (bb, '$')
    
    print (outputBuffer)

     At the end the result is printed on the terminal and can be copied and pasted on a text editor.

    It is a very crude script but it was enough for me. It is impressive what we can do with 40 lines of python ( nevermind the blank lines and comments)

    Screenshots

    The splash screen depends upon the slot where the ROM is inserted is even or odd. Both were inspired in Rock Bands.

    Even Slots: Queen
    Odd Slots: Information Society

    As it was mentioned before, the game needs at least 32K of RAM to be copied to memory. On some machines without RAM expansion the No RAM splash screen is shown

    Advert for machines with less than 32K of RAM

    Worth to mention that after the splash screen was added it was necessary to add 3 more seconds of delay...

    Read more »