Noteworthy topics, mostly technical
RCX Internals famously includes a C-like pseudocode version of the ROM and firmware version 0309 with extensive comments. This page aims to build on that work by providing pseudocode for firmware versions that, to my knowledge, don't already have publicly available decompilations. This will be helpful to see when features were added and bugs were fixed.
Most of the work here comes from my own automated disassemblies of the firmware files hosted at pbrick.info. Since the code blocks on this page are very large, I have put them into collapsible containers.
First let's look at the simple programs that are built into the ROM, the ones that are available to run without any firmware on the brick. There are 5 built-in programs, though some sources like pbrick.info incorrectly claim there are 3.
The ROM's main loop repeatedly calls the function rom_program_update() at address $0d8c whenever the brick is in its normal running state. Each of the five programs is implemented as a simple state machine.
RAM variables used by ROM programs:
ef10 - byte, program number (0-4 --> programs 1-5)
ef11 - byte, apparently unused
ef12 - sensorstruct, sensor 0 (port 1)
ef12 - byte, type
ef13 - byte, mode
ef14 - word, raw
ef16 - word, value
ef18 - byte, boolean
ef19 - byte, unused
ef1a - sensorstruct, sensor 1 (port 2)
ef1a - byte, type
ef1b - byte, mode
ef1c - word, raw
ef1e - word, value
ef20 - byte, boolean
ef21 - byte, unused
ef22 - sensorstruct, sensor 2 (port 3)
ef22 - byte, type
ef23 - byte, mode
ef24 - word, raw
ef26 - word, value
ef28 - byte, boolean
ef29 - byte, unused
ef2a - byte, motor state (low bit = dir, high bit = stop)
motor 0 (port A): bits 0x30
motor 1 (port B): bits 0xc0
motor 2 (port C): bits 0x03
ef2b - byte, walking figure state
ef2c - byte, button state (run: bit 0, prgm: bit 2)
ef2d - byte, program state
ef2e - word, random number
ef30 - byte, loop counter
// called when the ROM first boots up
$0d44 - rom_init_program()
{
random number$ef2e: word = 0xffff
button state$ef2c: byte = 0
program number$ef10: byte = 0
walking figure state$ef2b: byte = 0
sensor 0 type$ef12: byte = 0 // touch sensor
sensor 0 mode$ef13: byte = 0 // raw
sensor 1 type$ef1a: byte = 3 // light sensor
sensor 1 mode$ef1b: byte = 0x80 // percent
sensor 2 type$ef22: byte = 0 // touch sensor
sensor 2 mode$ef23: byte = 0 // raw
motor state$ef2a: byte = 0
program state$ef2d: byte = 0
return
}
// called whenever ROM main loop state = 0x0d
$0d8c - rom_program_update(r6=dataptr)
{
make room for 4 bytes on stack
if (task 0 wakeup delay$ee82: word == 0)
buttons = read_buttons() // ROM routine $1fb6
if (buttons & 1) // run button pressed?
if (bit 0 of button state$ef2c: byte is clear)
set bit 0 of button state$ef2c: byte
play sound 1 (double beep)
minutes to power off$ee80: word = 15
task 0 wakeup delay$ee82: word = 0x14 // 0.20 seconds
if (walking figure state$ef2b: byte == 0x01)
rom_program_stop()
else
walking figure state$ef2b: byte = 0x01
else
clear bit 0 of button state$ef2c: byte
if (buttons & 4) // prgm button pressed?
if (bit 2 of button state$ef2c: byte is clear)
set bit 2 of button state$ef2c: byte
program number$ef10: byte = (program number$ef10: byte + 1) % 5
rom_program_stop()
play sound 1 (double beep)
minutes to power off$ee80: word = 15
task 0 wakeup delay$ee82: word = 0x14 // 0.20 seconds
else
clear bit 2 of button state$ef2c: byte
// PRNG using a modified xorshift algorithm
bit = 0
if (random number$ef2e: word & 0x0002)
bit ^= 1
if (random number$ef2e: word & 0x0010)
bit ^= 1
if (random number$ef2e: word & 0x0040)
bit ^= 1
if (random number$ef2e: word & 0x2000)
bit ^= 1
random number$ef2e: word = (2 * random number$ef2e: word) | bit
// Store sensor data in the structs defined above
for (sensor = 0, sensor >= 3, ++sensor)
read_sensor(0x1000+sensor, 0xef12+8*sensor)
if (walking figure state$ef2b: byte == 0x01)
set LCD walking figure segments
else
set LCD standing figure segments
if (get_battery_voltage() <= 0x00df)
set LCD low battery indicator
else
clear LCD low battery indicator
clear all LCD port active indicators
if (motor state$ef2a: byte & 0x20)
if (motor state$ef2a: byte & 0x10)
set LCD motor 0 backward
else
set LCD motor 0 forward
if (motor state$ef2a: byte & 0x08)
if (motor state$ef2a: byte & 0x04)
set LCD motor 1 backward
else
set LCD motor 1 forward
if (motor state$ef2a: byte & 0x02)
if (motor state$ef2a: byte & 0x01)
set LCD motor 2 backward
else
set LCD motor 2 forward
if (sensor 0 boolean$ef18: byte != 0)
set LCD sensor 0 active
if (sensor 1 boolean$ef20: byte != 0)
set LCD sensor 1 active
if (sensor 2 boolean$ef28: byte != 0)
set LCD sensor 2 active
display program number on LCD
refresh_display() // full refresh - takes 1.5 ms
// This almost looks like a bug -
// program only updates when figure is walking?
if (walking figure state$ef2b: byte == 0)
goto end
// built-in program 1 at $0fe6
if (program number$ef10: byte == 0)
if (program state$ef2d: byte == 0)
play sound 1 (double beep)
++program state$ef2d: byte
else if (program state$ef2d: byte == 1)
motor 0 forward power 7
motor 2 forward power 7
motor state$ef2a: byte = 0x22
goto end
// built-in program 2 at $1050
if (program number$ef10: byte == 1)
if (program state$ef2d: byte == 0)
motor 0 forward power 7
motor 2 forward power 7
motor state$ef2a: byte |= 0x22
++program state$ef2d: byte
else if (program state$ef2d: byte == 1)
if (sensor 0 boolean$ef18: byte == 0)
motor 0 forward power 7
set bit 5 of motor state$ef2a: byte
else
motor 0 brake
clear bit 5 of motor state$ef2a: byte
if (sensor 2 boolean$ef28: byte == 0)
motor 2 forward power 7
set bit 1 of motor state$ef2a: byte
else
motor 2 brake
clear bit 1 of motor state$ef2a: byte
goto end
// built-in program 3 at $112e
else if (program number$ef10: byte == 2)
if (program state$ef2d: byte == 0)
motor 0 forward power 7
motor 2 forward power 7
motor state$ef2a: byte |= 0x22
++program state$ef2d: byte
else if (program state$ef2d: byte == 1)
set sensor 1 active
if (sensor 1 value$ef1e: word > 0x0032)
motor 0 forward power 7
motor 2 forward power 7
motor state$ef2a: byte |= 0x22
if (sensor 1 value$ef1e: word < 0x0028)
motor 0 brake
motor 2 brake
motor state$ef2a: byte &= ~0x22
goto end
// built-in program 4 at $120c
else if (program number$ef10: byte == 3)
if (program state$ef2d: byte == 0)
loop counter$ef30: byte = 5
++program state$ef2d: byte
else if (program state$ef2d: byte == 1)
if (loop counter$ef30: byte & 1)
motor 0 forward power 7
motor 2 forward power 7
motor state$ef2a: byte = 0x22
else
motor 0 reverse power 7
motor 2 reverse power 7
motor state$ef2a: byte = 0x33
task 2 wakeup delay$ee86: word = (random number$ef2e: word % 0x012c) // max 3.00 seconds
++program state$ef2d: byte
else if (program state$ef2d: byte == 2)
if (task 2 wakeup delay$ee86: word == 0)
if (loop counter$ef30: byte & 1)
motor 0 reverse power 7
motor state$ef2a: byte = 0x32
else
motor 0 forward power 7
motor state$ef2a: byte = 0x23
task 2 wakeup delay$ee86: word = (random number$ef2e: word % 0x012c) // max 3.00 seconds
++program state$ef2d: byte
else if (program state$ef2d: byte == 3)
if (task 2 wakeup delay$ee86: word == 0)
if (--loop counter$ef30: byte == 0)
rom_program_stop()
else
program state$ef2d: byte = 1
goto end
// built-in program 5 at $1344
else if (program number$ef10: byte == 4)
if (program state$ef2d: byte == 0)
motor 0 forward power 7
motor 2 forward power 7
motor state$ef2a: byte = 0x22
++program state$ef2d: byte
else if (program state$ef2d: byte == 1)
if (sensor 0 boolean$ef18: byte == 1)
motor 0 reverse power 7
motor 2 reverse power 7
motor state$ef2a: byte = 0x33
task 2 wakeup delay$ee86: word = 0x0064 // 1.00 second
++program state$ef2d: byte
else if (program state$ef2d: byte == 2)
if (task 2 wakeup delay$ee86: word == 0)
motor 0 forward power 7
motor state$ef2a: byte = 0x23
task 2 wakeup delay$ee86: word = 0x0032 // 0.50 seconds
++program state$ef2d: byte
else if (program state$ef2d: byte == 3)
if (task 2 wakeup delay$ee86: word == 0)
program state$ef2d: byte = 0
goto end
// $142a
end:
clear bit 7 of dispatch data$ee64: byte
clear r6
return
}
$1446 - rom_program_stop()
{
walking figure state$ef2b: byte = 0
program state$ef2d: byte = 0
motor state$ef2a: byte = 0
motor 0 brake
motor 2 brake
// bug? only sensor 1 was ever set active, but sensor 2 is turned off instead
set sensor 2 passive
return
}
TODO