Monday, July 15, 2013

Sega Machine Code Programming

In the previous post, we checked out Sega BASIC Programming and wrote some BASIC code on a modern-day computer using the Sega emulator Meka and a copy of the Sega BASIC Level 3 ROM.

As an example, we wrote the main loop of a simple "Shoot 'em up" game that simply moves a target sprite around the screen based on user input; preferably the joystick.

However, games written in BASIC suffer from the disadvantage that they are too slow for applications such as sprite movement; these may be sped up by increasing the step but precision of control is lost.

This can be resolved by using machine code routines for parts of the program where BASIC is too slow.
Goal: apply machine code routines to target Sega hardware directly for speed, efficiency and power.

Setup
Follow all instructions from previous post to get setup with Sega programming before continuing.

Launch Sega BASIC Level 3 ROM, that is, double click Sega BASIC Level 3 V1 (SC-3000) [b1].sc.
Activate keyboard to begin typing: Inputs menu, Sega Keyboard. Next, open the Memory Editor:
  • Tools menu
  • Memory Editor
  • Click RAM button
  • Type F000
Note: all machine code written during this post will commence at 16-bit memory address: &HF000.

Tutorial
Type in the following BASIC code:
10 POKE &HF000, &HC9
RUN
Inspect the 16-bit memory address &HF000; the hexadecimal &HC9 will now be stored in RAM there. Next, add the following line of code:
20 PRINT PEEK(&HF000)
RUN
The value 201 will be printed, which is the corresponding decimal value of &HC9, of course.

Finally, change line 20 of code to the following:
20 CALL &HF000
RUN
On the surface, nothing appears to happen! Therefore, let's delve into fundamentals of machine code:

Fundamentals
Machine code is a set of instructions executed directly by the computer Central Processing Unit (CPU). Each instruction performs a specific operation on a unit of data contained in CPU register, or memory.

In this post, we target the Sega SC-3000 hardware: an 8-bit home computer based on the Z80 chip.

Typically, machine code instructions are stored in memory and invoked from a BASIC driver program. Once invoked, machine code instructions are then executed one by one, similar to BASIC commands.

However, unlike BASIC, machine code will not automatically stop when it reaches the end of program. Machine code must execute the RET instruction to return to BASIC; very similar to RETURN in BASIC.

Opcodes
Each machine code instruction has a unique numerical code called an operation code, or an Opcode.
In the example above, the opcode for the RET instruction is 201 or &HC9 in hexadecimal.

Mnemonics
For completeness, RET is the called the Mnemonic; that is, the symbolic name for the instruction.

Dissection
Therefore, let's dissect the short code sample from above:
10 POKE &HF000, &HC9
20 CALL &HF000
RUN
  • Store opcode &HC9 into memory address &HF000
  • Invoke machine code routine at origin &HF000
  • Execute machine code instructions (only one)
  • Execute RET instruction: i.e. return to BASIC
Documentation
Check out here for the Z80 instruction set. Check out here for full (undocumented) Z80 Opcode list.
Many more tutorials can be found in magazine scans from Sega Survivors web site and SMS Power.

Books: the authoritative Programming the Z80 by Rodney Zaks and Mastering Machine Code (Z80).

Debugging
Before progressing with thorough machine code example, let's setup our environment for debugging: Make the change to the mekaw.cfg file: find debug_mode = 0 and replace with debug_mode = 1.

Launch Sega BASIC Level 3 ROM as before; there should now be additional DEBUG menu available. Choose: Debug menu, Enabled. Meka will break at the memory address at current code execution. Type "B F000" to set breakpoint at &HF000 Type "C" to continue Type RUN as before Program now invokes CALL &HF000 as before but this time breaks at breakpoint set above.
Hit the Enter key to step through the machine code: executes RET which returns to BASIC.

Note: for full list of Debugger commands choose: Help menu, Debugger.
Also, enter Up / Down arrow keys to scroll through command history.

Example
As an example, let's write the main loop of a simple "Shoot 'em up" style game, similar to the previous post, that simply moves a target sprite around the screen based on user input; preferably the joystick.

However, write the main loop in machine code for increased speed + performance, rather than BASIC.

Sample
The following code sample is reminiscent of the tutorial Joystick Operation using Machine Code Routine. Follow the tutorial closely to better understand what machine code instructions are required and why.

Type in the following program. Important: ensure you save state before RUN: Main menu, Save State.
10 REM SEGA MACHINE CODE PROGRAMMING
20 GOSUB 300:GOSUB 400
40 SZ=16:MAG1
60 MR=256-SZ:MD=192-SZ
70 TX=MR/2:TY=MD/2
80 SCREEN 2,2:CLS
90 COLOR,1,(0,0)-(255,191),1
100 REM MAIN LOOP
110 SPRITE 0,(TX,TY),0,9
120 CALL &HF000
130 STOP
300 RESTORE 350
310 FOR S=0 TO 3:READ S$:PATTERN S#S,S$:NEXT S
320 RETURN
350 DATA 000039202100012A, 2A01002120390000
360 DATA 00009C0484008054, 54800084049C0000
400 RESTORE 450
410 FOR X=&HF000 TO &HF036
420 READ A$:A=VAL(“&H”+A$):POKE X,A
430 NEXT X
440 RETURN
450 DATA 3E,9B,D3,DF,DB,DC,FE,FF,28,FA,FE,F7,20,10,21,01
460 DATA 3B,CD,32,2C,DB,BE,3C,CD,44,2C,D3,BE,18,0E,21,01
470 DATA 3B,CD,32,2C,DB,BE,3D,CD,44,2C,D3,BE,01,00,03,0B
480 DATA 3E,00,B8,20,FA,18,CD
RUN
The graphics screen clears black and positions a red target sprite. Use the joystick to move target sprite.
Note: de-activate the keyboard to ensure the joystick takes precedence: Inputs menu, Sega Keyboard.

In this example, moving joystick right moves target sprite right; moving any other direction moves left.
Important: if joystick not configured then try these keys: "J" = left, "M" = right, "7" = up, "U" = down. Note: the machine code here actually does not RET to BASIC; press the "Scroll lock" key to soft reset.

As you can see, the machine code version of the program is much smoother than its BASIC counterpart. In fact, machine code is so fast that a delay is required: without it, the sprite would simply flash across!

Experiment with different delay speeds at runtime by manipulating memory directly:
Note: original time delay is 0300 but is stored in memory as 00 03 (Little-endian).
  • Tools menu
  • Memory Editor
  • Click RAM button
  • Type F02E
  • Enter "02" (faster)
  • Enter "04" (slower)
For completeness, here is the disassembled machine code from the tutorial in its entirety:
--------------------------------------------------
Z80    DISASSEMBLER     LISTING
Line   Addr Opcodes     Label   Instruction
--------------------------------------------------
0000   0000             .ORG    0F000H
0001   F000 3E 9B       START:  LD A,09BH
0002   F002 D3 DF               OUT (0DFH),A
0003   F004 DB DC       CHECK:  IN A,(0DCH)
0004   F006 FE FF               CP 0FFH  ; any movement?
0005   F008 28 FA               JR Z,CHECK
0006   F00A FE F7       RIGHT:  CP 0F7H  ; move right?
0007   F00C 20 10               JR NZ,OTHER
0008   F00E 21 01 3B            LD HL,03B01H
0009   F011 CD 32 2C            CALL 02C32H 
0010   F014 DB BE               IN A,(0BEH)
0011   F016 3C                  INC A
0012   F017 CD 44 2C            CALL 02C44H
0013   F01A D3 BE               OUT (0BEH),A
0014   F01C 18 0E               JR DELAY
0015   F01E 21 01 3B    OTHER:  LD HL,03B01H
0016   F021 CD 32 2C            CALL 02C32H
0017   F024 DB BE               IN A,(0BEH)
0018   F026 3D                  DEC A
0019   F027 CD 44 2C            CALL 02C44H
0020   F02A D3 BE               OUT (0BEH),A
0021   F02C 01 00 03    DELAY:  LD BC,0300H
0022   F02F 0B          LOOP:   DEC BC
0023   F030 3E 00               LD A,00H
0024   F032 B8                  CP B
0025   F033 20 FA               JR NZ,LOOP
0026   F035 18 CD               JR CHECK
Important: machine code programs will crash if there are errors; they are not as forgiving as BASIC. Therefore, ensure you save state before you RUN machine code programs: Main menu, Save State.

Summary
In this post, machine code was introduced to target Sega hardware for increased speed + performance.

However, a machine code program suffers from the disadvantage that it is tedious and cumbersome to manually translate each mnemonic to the corresponding opcode plus calculate all jump relative offsets.

This can be resolved by using assembly language and an assembler to generate machine code routines. This will be the topic in the next post.

Thursday, July 4, 2013

Sega BASIC Programming

In the previous post, we checked out Sega Retro Gaming and some classic cartridge-based video games built on early 8-bit hardware such as the Sega SG-1000, the SC-3000 and the Sega Master System.

Now, we would like to write our own similar 8-bit retro games!

In this post, we will focus on the Sega SC-3000 home computer using the BASIC programming language for its simplicity and ease-of-use.

In order to write Sega BASIC code on a modern-day computer, you will need an emulator installed and a copy of the Sega BASIC Level 3 ROM, or Sega BASIC IIIb, as it's also known.

While there are many emulators available for Sega platforms, only one emulator seems to be compatible with the Sega BASIC Level 3 ROM, that is: Meka
  • Download mekaw073.zip and extract
  • Double click on mekaw.exe to launch
Note: check Debugger: Enable Z80 debugger for better developer experience.

Configuration
Meka may be challenging to work with, especially if you have dual monitors. In order to alternate windowed / full screen mode, make changes to the meka.blt file, similar to the following:
[HQ2X::WIN]
res = 1024x768
driver = auto_win
refresh_rate = 20
blitter = hq2x
stretch

  • Launch Meka
  • Video menu
  • Blitters
  • Select HQ2X
Note: press ESC to alternate windowed / full-screen mode.

Sega BASIC
Next, download the Sega BASIC Level 3 ROM:
26620 Bytes free – are you serious?!?

Setup
Each time Meka is launched, activate the Sega keyboard to begin typing:
  • Inputs menu
  • Sega Keyboard
Note: the Sega keyboard is not 100% compatible with typical QWERTY keyboard.
For example the "&" character is Shift+6 not Shift+7 on the Sega keyboard.

Hello World
Type in the first BASIC program: the obligatory "Hello World":
NEW
10 PRINT "HELLO WORLD"
20 GOTO 10
RUN
Hello World will be printed down the screen indefinitely. Press the "End" key to break.
Note: there can only be one active program in memory at any one time.

Shortcuts
Here is short list of keyboard shortcuts that may be useful when using the Sega BASIC Level 3 ROM:

Key
Scroll lock
End key
Arrow keys
Backspace
Shift + Backspace

Action
soft reset (keeps code in memory)
break current program execution
move cursor around text screen
delete character to left of cursor
insert character to right of cursor

Also, the Sega keyboard has a special function key that simplifies the typing of entire BASIC commands, for example, press of the "FUNC" key and one other key combination:

Command
LIST
RUN

Shortcut
Tab + Backspace
Tab + ` (backtick)
Note: shortcuts may be different depending on localization.

State
After typing in the first BASIC program, it will remain in memory until the Sega computer is powered off. In order to maintain program state across sessions, simply save state, close and load state next session.
  • Main menu
  • Save State
  • Close Meka
  • Launch Meka
  • Main menu
  • Load State
Note: file is stored at C:\PathToMeka\Saves\Sega BASIC Level 3 V1 (SC-3000) [b1].S00

Important: there can only be one copy of the state file at any one time.
Therefore, it is up to you to archive your state files accordingly!

Documentation
The Sega SC-3000 Survivors web site contains links to much documentation: manuals, magazines and books. SMS Power web site also has more magazines scans for Sega 8-bit preservation and fanaticism!

Example
As an example, let's write the main loop of a simple "Shoot 'em up" style game that simply moves a target sprite around the screen based on user input; preferably the joystick.

Controller
If you have a joystick connected to your computer, e.g. wireless Xbox 360 controller;
Configure the controller for best game play experience:
  1. Close Meka
  2. Activate controller
  3. Launch Meka
  4. Inputs menu
  5. Joypad checked
  1. Configuration
  2. Input Configuration
  3. Click ">>" twice
  4. 3/6 Joypad 1
  5. Enabled checked
Type in the following BASIC program to confirm the controller is configured correctly:
NEW
10 PRINT STICK(1)
20 GOTO 10
RUN
Zeros will be printed down the screen indefinitely: move the joystick in different directions;
Output: a value between 1 to 8 will be printed on-screen. Press the "End" key to break.

Sample
The following code sample is reminiscent of the Sega BASIC "Shoot 'em up" game titled "3D City" (1988). While we will not dissect the full program at this time, we will replicate the main loop accordingly.

Type in the following program exactly as is:
10 REM SEGA BASIC PROGRAMMING
20 GOSUB 300
30 ST=1
40 SZ=16:MAG1
50 ML=0:MU=0
60 MR=256-SZ:MD=192-SZ
70 TX=MR/2:TY=MD/2
80 SCREEN 2,2:CLS
90 COLOR,1,(0,0)-(255,191),1
100 REM MAIN LOOP
110 SPRITE 0,(TX,TY),0,9
120 VX=0:VY=0
130 S1=STICK(1):FR=STRIG(1):A$=INKEY$
140 IF S1=3 OR A$=CHR$(28) THEN VX=1:GOSUB 200
150 IF S1=7 OR A$=CHR$(29) THEN VX=-1:GOSUB 200
160 IF S1=1 OR A$=CHR$(30) THEN VY=-1:GOSUB 200
170 IF S1=5 OR A$=CHR$(31) THEN VY=1:GOSUB 200
180 IF FR=1 OR A$=CHR$(32) THEN END
190 GOTO 100
200 REM MOVEMENT
210 VX=VX*ST:VY=VY*ST
220 TX=TX+VX:TY=TY+VY
230 IF TX <= ML THEN TX=ML
240 IF TX >= MR THEN TX=MR
250 IF TY <= MU THEN TY=MU
260 IF TY >= MD THEN TY=MD
270 RETURN
300 RESTORE 350
310 FOR S=0 TO 3:READ S$:PATTERN S#S,S$:NEXT S
320 RETURN
350 DATA 000039202100012A, 2A01002120390000
360 DATA 00009C0484008054, 54800084049C0000
RUN
The graphics screen clears black and positions a red target sprite. Use the controller, or arrow keys, to move the target sprite left, right, up and down. Press the left fire button or space bar to end program. As you can see, the current per-pixel sprite movement is smooth but extremely slow!
Therefore, increase the movement step; change line 30 of the code to the following:
30 ST=2        30 ST=4        30 ST=8        30 ST=16        etc.
RUN

Also, the movement step can be changed dynamically at runtime by manipulating memory directly:
  • Tools menu
  • Memory Editor
  • Click RAM button
  • Type EFF0
  • Enter "01"
Note: &HEFF0 is the 16-bit memory address where ST will be manipulated.
Next, add the following lines of code to the original program:
34 AD=&HEFF0
38 POKE AD,ST
205 ST=PEEK(AD)
RUN
Program runs as before. However, this time experiment: enter hexadecimal values at the Memory Editor address &HEFF0 for example: 02, 04, 08, 10 etc. to see the movement step effects on the target sprite.

Finally, save the state of Meka for future use: Main menu, Save State.

Summary
In this post, BASIC programming was introduced on the Sega SC-3000 for simplicity and ease-of-use.

However, games written in BASIC suffer from the disadvantage that they are too slow for applications such as sprite movement; these may be sped up by increasing the step but precision of control is lost.

This can be resolved by using machine code routines for parts of the program where BASIC is too slow. This will be the topic in the next post.