Forums

Sega Master System / Mark III / Game Gear
SG-1000 / SC-3000 / SF-7000 / OMV
Home - Forums - Games - Scans - Maps - Cheats - Credits
Music - Videos - Development - Hacks - Translations - Homebrew

View topic - SG-1000 port DE write/read at boot pattern

Reply to topic
Author Message
  • Joined: 15 Sep 2019
  • Posts: 4
Reply with quote
SG-1000 port DE write/read at boot pattern
Post Posted: Sun Sep 15, 2019 9:00 am
I'm debugging my SG-1000 emulator and suspect that the PPI may be to blame. I keep seeing a pattern at boot time in game ROMs that I don't understand, and I'd like to be able to rule it out as a possible issue.

Lots of ROMs seem to write a known value to port DE (PPI port C write) then read it back (PPI port C read) and store state depending on whether the same value is returned. This state is then read in the per-frame input routine. What does this state mean?

The only information I have been able to find is

Quote
Some software will write data to ports $DE and $DF. The SG-1000 and SC-3000 had an 8255 PPI which used these ports to control a keyboard, but later consoles got rid of it. There is a keyboard peripheral for the Mark III, which perhaps some games try to detect and use.


Quote
When port C is configured as an output, reading it returns the last value written to port C


From smspower>Development>Keyboard and smstech-20021112.txt

For example:


; Space invaders
0548   ld      hl, 0C004h
054B   set     0, (hl)
054D   xor     a
054E   out     (0DEh), a
0550   in      a, (0DEh)
0552   or      a
0553   ret     z
0554   res     0, (hl)
0556   ret

; Champion Golf
0B99  ld      a, 0A2h
0B9B  out     (0DEh), a       ; PPI I/O port C write. Select input row 2
0B9D  in      a, (0DEh)       ; 8255 PPI I/O port C read
0B9F  cp      0A2h            ; read same value back?
0BA1  jr      z, BA9
0BA3  xor     a               ; a <- 0
0BA4  ld      (C247h), a
0BA7  jr      BAE
0BA9  ld      a, 1
0BAB  ld      (C247h), a
0BAE  ret


; Q-bert checks twice
0017  ld      a, 55h
0019  out     (DEh), a
001B  in      a, (DEh)
001D  cp      55h
001F  jr      nz, 2D
0021  cpl
0022  out     (DEh), a
0024  in      a, (DEh)
0026  cp      0AAh
0028  jr      nz, 2D
002A  ld      (C079h), a
  View user's profile Send private message
  • Joined: 05 Nov 2014
  • Posts: 277
  • Location: Auckland - NZ
Reply with quote
Post Posted: Mon Sep 16, 2019 1:51 am
This may be of use..

http://www.smspower.org/uploads/Development/sc3000h-20040729.txt

In respect to..

Quote
Most software writes $92 to the PPI control register and $07 to PPI port C,
which configures ports A and B as inputs and all bits of port C as outputs,
as well as selecting row 7 of the keyboard matrix to access the gamepads.

When port C is configured as an output, reading it returns the last value
written to port C. The PPI control register cannot be read, and always
returns $FF.
  View user's profile Send private message
  • Joined: 15 Sep 2019
  • Posts: 4
Reply with quote
Post Posted: Tue Sep 17, 2019 6:42 am
Thanks. It seems strange that games configure PPI Port C as output, but then go on to test that it returns the last value written. There must be some situation in which it does not.

Perhaps this is testing for the presence of a keyboard, or testing if the game is running on a particular machine?
  View user's profile Send private message
  • Joined: 05 Nov 2014
  • Posts: 277
  • Location: Auckland - NZ
Reply with quote
Post Posted: Tue Sep 17, 2019 7:01 am
Could be to check if its running on a sg-1000/mkIII with or without a keyboard..and or a sc-3000 i guess.
  View user's profile Send private message
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 12988
  • Location: London
Reply with quote
Post Posted: Tue Sep 17, 2019 7:18 am
I thought the point was to have the game be controllable by the keyboard.
  View user's profile Send private message Visit poster's website
  • Joined: 28 Sep 1999
  • Posts: 1149
Reply with quote
Post Posted: Wed Sep 18, 2019 3:32 pm
HowPrice wrote
Thanks. It seems strange that games configure PPI Port C as output, but then go on to test that it returns the last value written. There must be some situation in which it does not.


I think it's a keyboard check. The SK-1100 keyboard you plug in adds the missing PPI:

https://web.archive.org/web/20090213004805/http://www2.odn.ne.jp/~haf09260/Mark3...
(Btw, what a shame Enri's page is down)

When the keyboard is attached port C exists and can be read and written. When it is removed there is no port C so you read an open bus value, probably 00, FF, random, etc. Which may be why games check twice to be sure.

I think they check port C this instead of testing the mode register at $DF because earlier NMOS PPIs had a mode register you couldn't read, and read-back functionality was only added later to the CMOS PPIs as I recall. This leaves port C as the only PPI register that can be read and written.
  View user's profile Send private message Visit poster's website
  • Joined: 15 Sep 2019
  • Posts: 4
Reply with quote
Post Posted: Wed Sep 18, 2019 9:22 pm
Thanks Charles. That makes a lot of sense. I wish I understood electronics, and Japanese. I've identified the input routines in Space Invaders, which I'm using to debug my emulator, so I hope to confirm this soon. I've almost figured it out.


; =============== S U B R O U T I N E =======================================

0544              ; Standard PPI setup
0544              ; Set C004 bit high if SK-1100 keyboard connected
0544              InitInput:                              ; CODE XREF: 009E
0544  3E 92                       LD A,92                 ; PPI Control Register write
0546  D3 DF                       OUT ($DF),A             ; Port A and B input, port C output
0548  21 04 C0                    LD HL,C004
054B  CB C6                       SET 0,(HL)              ; C004 bit 0 high means keyboard connected
054D  AF                          XOR A                   ; A <- 0
054E  D3 DE                       OUT ($DE),A             ; write 0 to PPI port C
0550  DB DE                       IN A,($DE)              ; Read port C back...
0552  B7                          OR A                    ; read same value back?
0553  C8                          RET Z                   ; yes = SK-1100 keyboard connected
0554  CB 86                       RES 0,(HL)              ; C004 bit 0 low means no keyboard connected
0556  C9                          RET
; ---------------------------------------------------------------------------

; =============== S U B R O U T I N E =======================================

05A3              UpdateInput:                            ; CODE XREF: 0232
05A3                                                      ; CODE XREF: 057B
05A3  3A 04 C0                    LD A,(byte_C004)
05A6  0F                          RRCA                    ; Carry flag = Accumulator bit 0 = keyboard connected
05A7  38 1D                       JR C,Player1Input       ; jump if keyboard connected
05A9  0F                          RRCA                    ; Rotate Accumulator Right
05AA  38 08                       JR C,ReadPad2           ; read pad 2 if C004 bit 1 set
05AC  DB DC                       IN A,($DC)              ; PPI port A read
05AE  F6 C0                       OR C0                   ; discard pad 2 bits (active low)
05B0  32 0F C0                    LD (byte_C00F),A        ; store joypad 1 bits in C00F
05B3  C9                          RET
; ---------------------------------------------------------------------------


; =============== S U B R O U T I N E =======================================

05B4              ; Pad 2 bits are split across PPI port A and port B values so need logic to combine
05B4              ReadPad2:                               ; CODE XREF: 05AA
05B4                                                      ; CODE XREF: 0620
05B4  DB DC                       IN A,($DC)              ; PPI port A read
05B6  E6 C0                       AND C0                  ; discard pad 1 bits - keep only pad 2 bits
05B8  47                          LD B,A
05B9  DB DD                       IN A,($DD)              ; PPI port B read (joypad 2 bits)
05BB  E6 3F                       AND 3F
05BD  80                          ADD A,B                 ; combine: DUxxBARL
05BE  07                          RLCA                    ; UxxBARLD
05BF  07                          RLCA                    ; xxBARLDU
05C0  F6 C0                       OR C0                   ; 11BARLDU
05C2  32 0F C0                    LD (byte_C00F),A
05C5  C9                          RET
; ---------------------------------------------------------------------------

05C6              Player1Input:                           ; CODE XREF: 05A7
05C6  0F                          RRCA                    ; Rotate Accumulator Right
05C7  38 53                       JR C,Player2Input       ; test C004 bit 1
05C9              ; Combine joypad 1 and keyboard cursor input and store in C00F
05C9              ; Bits: xxBARLDU (active low)
05C9  3E 07                       LD A,07                 ; select PPI input row 7 (joypads)
05CB  D3 DE                       OUT ($DE),A             ; PPI Port C write
05CD  DB DC                       IN A,($DC)              ; PPI port A read
05CF  F6 C0                       OR C0                   ; discard pad 2 bits (active low)
05D1  32 0F C0                    LD (byte_C00F),A        ; store pad 1 state in C00F
05D4  4F                          LD C,A
05D5  3E 04                       LD A,04                 ; select PPI input row 4 (keyboard)
05D7  D3 DE                       OUT ($DE),A
05D9  DB DC                       IN A,($DC)              ; PPI port A read
05DB  CB 6F                       BIT 5,A                 ; test keyboard down arrow
05DD  20 02                       JR NZ,loc_05E1          ; skip next instruction if not pressed
05DF  CB 89                       RES 1,C                 ; bit 1 = down
05E1              loc_05E1:                               ; CODE XREF: 05DD
05E1  3E 05                       LD A,05                 ; select input row 5 (keyboard)
05E3  D3 DE                       OUT ($DE),A
05E5  DB DC                       IN A,($DC)
05E7  CB 6F                       BIT 5,A                 ; test keyboard left arrow
05E9  20 02                       JR NZ,loc_05ED          ; skip next instruction if not pressed
05EB  CB 91                       RES 2,C                 ; bit 2 = left
05ED              loc_05ED:                               ; CODE XREF: 05E9
05ED  3E 06                       LD A,06                 ; test keyboard right arrow...
05EF  D3 DE                       OUT ($DE),A
05F1  DB DC                       IN A,($DC)
05F3  CB 6F                       BIT 5,A
05F5  20 02                       JR NZ,loc_05F9
05F7  CB 99                       RES 3,C                 ; bit 3 = right
05F9              loc_05F9:                               ; CODE XREF: 05F5
05F9  CB 77                       BIT 6,A                 ; test keyboard up arrow...
05FB  20 02                       JR NZ,loc_05FF
05FD  CB 81                       RES 0,C
05FF              loc_05FF:                               ; CODE XREF: 05FB
05FF  3E 02                       LD A,02                 ; row 2
0601  D3 DE                       OUT ($DE),A
0603  DB DC                       IN A,($DC)
0605  CB 67                       BIT 4,A                 ; HOME CLR key
0607  20 02                       JR NZ,loc_060B
0609  CB A1                       RES 4,C                 ; bit 4 = button A
060B              loc_060B:                               ; CODE XREF: 0607
060B  3E 03                       LD A,03                 ; row 3
060D  D3 DE                       OUT ($DE),A
060F  DB DC                       IN A,($DC)
0611  CB 67                       BIT 4,A                 ; INS DEL key
0613  20 02                       JR NZ,loc_0617
0615  CB A9                       RES 5,C                 ; bit 5 = button B
0617              loc_0617:                               ; CODE XREF: 0613
0617  79                          LD A,C
0618  32 0F C0                    LD (byte_C00F),A
061B  C9                          RET
; ---------------------------------------------------------------------------

061C              Player2Input:                           ; CODE XREF: 05C7
061C  3E 07                       LD A,07                 ; select input row 7 (joypads)
061E  D3 DE                       OUT ($DE),A
0620  CD B4 05                    CALL ReadPad2
0623  4F                          LD C,A                  ; C <- pad 2 bits 11BARLDU
0624  3E 01                       LD A,01                 ; row 1
0626  D3 DE                       OUT ($DE),A
0628  DB DC                       IN A,($DC)
062A  CB 57                       BIT 2,A                 ; S key
062C  20 02                       JR NZ,loc_0630
062E  CB 91                       RES 2,C
0630              loc_0630:                               ; CODE XREF: 062C
0630  CB 5F                       BIT 3,A                 ; X key
0632  20 02                       JR NZ,loc_0636
0634  CB 89                       RES 1,C
0636              loc_0636:                               ; CODE XREF: 0632
0636  3E 02                       LD A,02                 ; row 2
0638  D3 DE                       OUT ($DE),A
063A  DB DC                       IN A,($DC)
063C  CB 4F                       BIT 1,A                 ; E key
063E  20 02                       JR NZ,loc_0642
0640  CB 81                       RES 0,C
0642              loc_0642:                               ; CODE XREF: 063E
0642  3E 03                       LD A,03                 ; row 3
0644  D3 DE                       OUT ($DE),A
0646  DB DC                       IN A,($DC)
0648  CB 57                       BIT 2,A                 ; F key!
064A  20 02                       JR NZ,loc_064E
064C  CB 99                       RES 3,C
064E              loc_064E:                               ; CODE XREF: 064A
064E  3E 05                       LD A,05                 ; row 5
0650  D3 DE                       OUT ($DE),A
0652  DB DD                       IN A,($DD)
0654  CB 5F                       BIT 3,A                 ; N key
0656  20 02                       JR NZ,loc_065A
0658  CB A9                       RES 5,C
065A              loc_065A:                               ; CODE XREF: 0656
065A  3E 06                       LD A,06                 ; row 6
065C  D3 DE                       OUT ($DE),A
065E  DB DD                       IN A,($DD)
0660  CB 57                       BIT 2,A                 ; J Key
0662  20 02                       JR NZ,loc_0666
0664  CB A1                       RES 4,C
0666              loc_0666:                               ; CODE XREF: 0662
0666  79                          LD A,C
0667  32 0F C0                    LD (byte_C00F),A
066A  C9                          RET
; ---------------------------------------------------------------------------
  View user's profile Send private message
  • Joined: 05 Nov 2014
  • Posts: 277
  • Location: Auckland - NZ
Reply with quote
Post Posted: Thu Sep 19, 2019 2:47 am
Charles MacDonald wrote
I think it's a keyboard check. The SK-1100 keyboard you plug in adds the missing PPI:

https://web.archive.org/web/20090213004805/http://www2.odn.ne.jp/~haf09260/Mark3...
(Btw, what a shame Enri's page is down)

When the keyboard is attached port C exists and can be read and written. When it is removed there is no port C so you read an open bus value, probably 00, FF, random, etc. Which may be why games check twice to be sure.


Ive been looking into this a bit too and its interesting the way its done.

On a SC-3000, the controller ports are read directly from the keyboard PPI.

On a SG-1000/MkIII the controller ports are read with logic. There is some address decoding logic that enables the controller ports during a read.

Once a SK1100 keyboard gets plugged in, the PPI on the keyboard takes control and decides when the controller ports can be read instead. Its still using logic for the controller ports, and not the PPI like on the SG-3000, but the output enable signal for the controller logic comes from the PPI rather than the address decoding logic, as it would without the keyboard being plugged in.

Based on that, if you plug a keyboard in, the PPI needs to be configured for the controller ports to be able to be read properly. This will be why they need to detect for it.
  View user's profile Send private message
  • Joined: 15 Sep 2019
  • Posts: 4
Reply with quote
Post Posted: Thu Sep 19, 2019 5:05 pm
I can see now that it is important for software to test for the presence of a keyboard on the SG-1000. If it didn't then each time port A and B were read, the controller data would be returned, regardless of the last value written to port C. This would be disasterous in code like the Space Invaders snippet above which combines controller + keyboard input.

For the purposes of emulation, I think it will be enough to add a keyboard present boolean to the machine/PPI. If present then port C read will return the last value written to port C. If the keyboard is not present, it might make sense to return the complement of the last value written, so it is guaranteed not to be the same value that was written.

EDIT: Just tried this and it works a treat.

Thanks!
  View user's profile Send private message
  • Site Admin
  • Joined: 08 Jul 2001
  • Posts: 8120
  • Location: Paris, France
Reply with quote
Post Posted: Fri Sep 20, 2019 8:37 am
The SF-7000 Users Manual has information about this
http://www.smspower.org/Scans/SF7000-Hardware-UsersManual

From Page 196
http://www.smspower.org/Scans/SF7000-Hardware-UsersManual?gallerypage=196
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 12988
  • Location: London
Reply with quote
Post Posted: Fri Sep 20, 2019 9:26 am
Hmm, we need to OCR that for better searchability...
  View user's profile Send private message Visit poster's website
Reply to topic



Back to the top of this page

Back to SMS Power!