It is currently Tue Oct 17, 2017 2:44 am

All times are UTC - 7 hours



Forum rules


Related:



Post new topic Reply to topic  [ 58 posts ]  Go to page Previous  1, 2, 3, 4
Author Message
PostPosted: Fri Feb 06, 2015 5:32 pm 
Offline
User avatar

Joined: Thu Dec 25, 2014 10:26 pm
Posts: 309
Location: Canada
tepples wrote:
koitsu wrote:
While describing each of the bits in an MMIO register the way you do is understandable (for quick reference), I imagine most people doing development fall into two categories: a) not knowing what the bits do + already have something open (PDF, etc.) that documents them, or b) know what the bits do and don't need the quick reference.
I need the quick reference to save me from having to pull up Fullsnes all the time. You might notice I did the same with "pin8gba.h" back when I was homebrewing for GBA.
I don't know about anyone else, but a good chunk of the reference documents I've used have been scattered into my source code as comments just so that I don't have to keep looking them up constantly.
Myask wrote:
Normally, unrolled loops and heavy-duty for-time optimization are for either a. time-critical code (like in VBLANK on NES) and b. oft-called code. Initialization is neither, and tens of loop iterations are going to lose negligible time.
Honestly I'm inclined to agree with Myask's point of view. The time difference is irrelevant but loops would save (a tiny amount of) precious rom space. For the purpose of an instructional example though I would say it's better to store them all manually if only so you can comment along the way and explain each one. They're both easy for me to read but for someone new I think the loops would be an unnecessary complication...

By the way, there's a lot of talk of using ca65 instead of wla around here. Is there something wrong with wla that I should know about?


Top
 Profile  
 
PostPosted: Fri Feb 06, 2015 5:36 pm 
Offline
User avatar

Joined: Sat Jul 12, 2014 3:04 pm
Posts: 936
Someone had problems lately. But I'm not sure if they were using up-to-date builds, which also got posted here lately.


Top
 Profile  
 
PostPosted: Fri Feb 06, 2015 5:38 pm 
Offline
User avatar

Joined: Mon Sep 15, 2014 4:35 pm
Posts: 3071
Location: Nacogdoches, Texas
Yes. The .base directive is broken and messes with hirom and, more importantly, look at what happened here: (according to my code, the registers that I stored information into are the same one I loaded from, but when WLA assembled it, it went to the wrong register for some reason unknown.)

psycopathicteen wrote:
I just learned something new. WLA is a total piece of crap.

Quote:
0082ea ldy #$0000 A:0000 X:0000 Y:0000 S:1fff D:0000 DB:00 nvMxdiZC V:230 H: 30
0082ed ldx #$8401 A:0000 X:0000 Y:0000 S:1fff D:0000 DB:00 nvMxdiZC V:230 H: 54
0082f0 sty $1808 [001808] A:0000 X:8401 Y:0000 S:1fff D:0000 DB:00 NvMxdizC V:230 H: 78
0082f3 stx $180a [00180a] A:0000 X:8401 Y:0000 S:1fff D:0000 DB:00 NvMxdizC V:230 H: 118
0082f6 jsr $820e [00820e] A:0000 X:8401 Y:0000 S:1fff D:0000 DB:00 NvMxdizC V:230 H: 158
00820e php A:0000 X:8401 Y:0000 S:1ffd D:0000 DB:00 NvMxdizC V:230 H: 204
00820f rep #$10 A:0000 X:8401 Y:0000 S:1ffc D:0000 DB:00 NvMxdizC V:230 H: 226
008211 sep #$20 A:0000 X:8401 Y:0000 S:1ffc D:0000 DB:00 NvMxdizC V:230 H: 248
008213 ldy $08 [000008] A:0000 X:8401 Y:0000 S:1ffc D:0000 DB:00 NvMxdizC V:230 H: 270
008215 ldx $0a [00000a] A:0000 X:8401 Y:0000 S:1ffc D:0000 DB:00 nvMxdiZC V:230 H: 302
008217 lda $00,x [000000] A:0000 X:0000 Y:0000 S:1ffc D:0000 DB:00 nvMxdiZC V:230 H: 334
008219 beq $822e [00822e] A:0000 X:0000 Y:0000 S:1ffc D:0000 DB:00 nvMxdiZC V:230 H: 364
00822e plp A:0000 X:0000 Y:0000 S:1ffc D:0000 DB:00 nvMxdiZC V:230 H: 386
00822f rts A:0000 X:0000 Y:0000 S:1ffd D:0000 DB:00 NvMxdizC V:230 H: 414

There's also some other minor things, but these are the main problems I've seen.

Quote:
Someone had problems lately. But I'm not sure if they were using up-to-date builds, which also got posted here lately.

That someone being me. And yes, I was using an up-to-date build, it's just that the aforementioned problems still haven't been fixed. :?


Top
 Profile  
 
PostPosted: Fri Feb 06, 2015 5:53 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
It's a "hot-button issue" because:

1) This kind of thing used to happen back in the 90s snesdev days, where "newcomers" would somehow latch on to (get overly obsessed with) the init routine and start "optimising it" even though it doesn't need optimising (just do the register sets like Nintendo says and be done with it). I'm not kidding when I say I must have seen this 20 times during the snesdev days, and a scary number recently as well (covered below),

2) There was a recent thread about it where a bunch of people showed up to try and "optimise" (and some routines flat out had bugs in them) -- to me, it's just another rehash of #1, 20+ years later,

3) The code being mentioned/referenced in a different thread contained two separate init routines (InitSNES.asm and InitSNES2.asm), where the comments indicate they're written by the same person, but I think one of them might be from bazz (fellow here on the forum), not sure (and if not, then that means there are at least 3 routines floating around), followed in that same thread by this (which I can't figure out -- maybe it was meant for another thread, I don't know, but once again focusing on the Init routine...), followed by even ANOTHER routine being written (this time using the lda/tcd technique -- I said fine, go ahead and do it because I'm just about finished with all of this, but there's just no point to doing it that way).

I want people to seriously look at the 16bit table indexing problem thread and actually take the time to look at what a newcomer to SNES development goes through. I want people to stop their brains, sit down, and imagine being Espozo. I want people to think about how frustrating it must be to get some code handed to you only to not understand a ton of it -- even an init routine -- because it's written "fancy" when it doesn't need to be (with regards to the init routine). Please do not forget the subject line of THIS thread! This is TRAINING MATERIAL! Keep it simple/clear!

Any arguments about "saving ROM space" I'll ignore simply because they're silly (just my opinion) -- unlike the NES/FC, there are very few SNES/SFC games that were extremely tight with ROM space and thus required the programmer to say "hey I know, I'll try to save some bytes by 'optimising the power-on init routine'". There are bigger fish to worry about. In those situations, the primary focus becomes "how can I decrease my data size (graphics, structures, etc.)" and often resulted in some simple form of compression (e.g. RLE) to deal with it. The init routine isn't a focus.

I hope this clears up why it's a "hot-button issue" for me. The power-on register init routine is something that a programmer should write once (and it's already been written, a zillion years ago, and does not need changing), total focus time maybe 30 seconds. If this was a discussion about VRAM clear/init, CGRAM clear/init, OAM clear/init, WRAM clear/init, then that's all fine and dandy (using DMA is usually the best way to nuke those though, given that you have to write a general DMA macro or subroutine for general use anyway). But the power-on/reset init is something that doesn't need this degree of focus, yet for whatever reason people latch on to it, and continue to latch on to it 20 years later, despite needing absolutely none of this focus.


Top
 Profile  
 
PostPosted: Fri Feb 06, 2015 10:23 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19084
Location: NE Indiana, USA (NTSC)
Khaz wrote:
The time difference is irrelevant but loops would save (a tiny amount of) precious rom space.

ROM space was precious on Atari 2600. It's not quite as precious on Super NES, where the launch titles were literally 128 times as big. But that's why I used the Squenix D=$2100 (saves one byte per write) and 16-bit STZs (cuts about a quarter of the writes).

Quote:
For the purpose of an instructional example though I would say it's better to store them all manually if only so you can comment along the way and explain each one.

Here's the explanation I put in docs/init.txt:
Code:
A valid Super NES program must write to all writable ports in the
S-CPU I/O and S-PPU at the start of a program.  This way, the
machine starts in a known state.  The code in init.s establishes
the following initial state:

S-CPU registers

A, X, Y: unspecified
Program bank: main >> 16
Data bank: unspecified (programs might want to PHK PLB)
P: decimal mode off, width 16-bit
S: $01FF
D: $0000

S-CPU I/O

4200=00         Disable vblank NMI and htime/vtime IRQ
4201=FF         Set pin 6 of controller ports high
4202=00         Multiply 0 by 0
4203=00
4204=00         Divide 0 by 0 (OH SHI--)
4205=00
4206=00
4207=00         htime = top of picture
4208=00
4209=00         vtime = left side of scanline
420A=00
420B=00         Stop DMA copies
420C=00         Stop HDMA
420D=00         Access $808000-$FFFFFF as slow ROM

S-PPU

2100=80         Forced blanking
2101=00         Sprites 8x8 and 16x16, patterns at $0000-$1FFF
2102=00         OAM address: $0000
2103=00
2104: skip      OAM write port
2105=00         Background mode 0, all layers using 8x8 pixel tiles
2106=00         Mosaic off
2107=00         BG1 nametable at $0000, 1x1 screen
2108=00         BG2 nametable at $0000, 1x1 screen
2109=00         BG3 nametable at $0000, 1x1 screen
210A=00         BG4 nametable at $0000, 1x1 screen
210B=00         BG1 and BG2 tiles at $0000
210C=00         BG3 and BG4 tiles at $0000
210D=00 00      BG1 scroll at (0, 1).  The S-PPU skips the first line
210E=00 00      of the picture, so Y=0 means start at line 1 of BG.
210F=00 00      BG2 scroll at (0, 1)
2110=00 00
2111=00 00      BG3 scroll at (0, 1)
2112=00 00
2113=00 00      BG4 scroll at (0, 1)
2114=00 00
2115=80         Add 1 word to VRAM address after high byte write
2116=00         VRAM address starts at 0
2117=00
2118-9: skip    VRAM write port
211A=00
211B=00 01      Set the mode 7 matrix to the identity matrix
211C=00 00      [ 1.0  0.0 ]
211D=00 00      [ 0.0  1.0 ]
211E=00 01
211F=00 00      Mode 7 scroll at (0, 0)
2120=00 00
2121=00         CGRAM address = 0
2122: skip      CGRAM write port
2123=00         Disable windows on BG1 and BG2
2124=00         Disable windows on BG3 and BG4
2125=00         Disable windows on sprites and blending
2126=00         Window 1 left side = 0
2127=00         Window 1 right side = 0
2128=00         Window 2 left side = 0
2129=00         Window 2 right side = 0
212A=00         Combine background windows using OR logic
212B=00         Combine sprites and blending using OR logic
212C=00         Enable no layers on main screen
212D=00         Enable no layers on sub screen
212E=00         Disable no layers on main screen within the window
212F=00         Disable no layers on sub screen within the window
2130=30         Disable blending and 332 palette
2131=00         Disable blending for all layers
2132=E0         Set entire COLDATA to 0
2133=00         Disable interlace and pseudo-hires, 224 lines


Espozo wrote:
[In WLA,] The .base directive is broken and messes with hirom

So does this template, which is designed for LoROM. I want to make sure it's free of poor practices before I try making a HiROM version.

koitsu wrote:
If this was a discussion about VRAM clear/init, CGRAM clear/init, OAM clear/init, WRAM clear/init, then that's all fine and dandy

OAM and nametables are cleared in ppuclear.s. CGRAM and pattern tables aren't cleared, but colors and tiles are DMA'd into memory in bg.s (for background) and player.s (for sprites). WRAM clear is one of those holy wars; tokumaru probably has a different point of view from the inventors of C.


Top
 Profile  
 
PostPosted: Fri Feb 06, 2015 10:39 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
That doc file looks beautiful and wonderful, tepples. I fully wholeheartedly approve. Big, BIG thumbs up.

The only thing I think might be wrong in it is the program bank (K). That should be $00 on power-on. That's because the CPU starts up in 65c02 emulation mode. The programmer should sei/clc/xce/jml to the next instruction (this sets K). phk/plb after is also recommended as you state, but up to the programmer based on their needs.

Also, just a general thing, but you should also do a long jump inside of your NMI. It ensures that your NMI will execute out of bank $80, thus getting the benefits from fastrom (3.58MHz). I recommend people do this regardless if mode 20, mode 21, slowrom, or fastrom -- it's a good habit in general, and harmless in non-fastrom modes.

I've attached the official documentation on why both of these needed. The ~ (tilde) on the end of the JMP instructions are to indicate to the Nintendo-sanctioned assembler to use a 24-bit long jump, thus setting K. Edit: sorry, I guess both are technically "65816 things", it's just that I'm used to the memory map on the IIGS and I've never experimented with fastrom on the SNES. (Guilty admission: I used to think you could just toggle CPU speed through that one SNES MMIO register and "everything would work", it wasn't until I got access to developers docs that explained only certain banks operate at high speed)


Attachments:
caution14.png
caution14.png [ 26.79 KiB | Viewed 2078 times ]
caution15.png
caution15.png [ 31.84 KiB | Viewed 2078 times ]
Top
 Profile  
 
PostPosted: Fri Feb 06, 2015 11:19 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19084
Location: NE Indiana, USA (NTSC)
You mean like this excerpt from my current init code?
Code:
; Make sure these conform to the linker script (e.g. lorom256.cfg).
ZEROPAGE_BASE = $0000
STACK_BASE = $0100
STACK_SIZE = $0100
LAST_STACK_ADDR = STACK_BASE + STACK_SIZE - 1

PPU_BASE = $2100
CPUIO_BASE = $4200

.segment "CODE"
.proc resetstub
  sei  ; turn off IRQs
  clc
  xce  ; turn off 6502 emulation mode
  jml reset_fastrom
.endproc

.segment "CODE7"
.proc reset_fastrom
  rep #$38   ; go to 16-bit binary mode
  ldx #LAST_STACK_ADDR
  txs        ; set the stack pointer

  ; Initialize the CPU I/O registers to predictable values
  lda #CPUIO_BASE     ; temporarily move direct page
  tcd
  ; 8< 8< 8< a bunch of stuff omitted >8 >8 >8

  lda #ZEROPAGE_BASE  ; return direct page to real zero page
  tcd
  jml main   ; this is why I say the program bank is main >> 16
.endproc


The Game Boy Advance has three different mirrors of ROM that can be set to operate at different speeds. It boots in slow ROM mode (wait states 4n/2s), and most games switch the main mirror to fast ROM (3n/1s). The SuperCard adapter doesn't support fast ROM, so writes to the speed control register actually have to be patched out. I'm not aware of any GBA game that uses fastest ROM (2n/1s), but later GBA flash cartridges support it for enhanced frame rate in 3D games.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 5:49 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
Looks right to me. I was about to throw a tiny tantrum about resetstub being in segment CODE while reset_fastrom was in segment CODE7, but I understand why you did that (and I was going to write a rebuttal against it, but after some deep thought, I figured that actually makes the most overall sense). I'll assume that the template sets CODE7 to bank $80 or at least between bank $80-FF.

Just please remember that the lorom256k.cfg template I saw (when doing stuff for Espozo) used MAPPER_LOROM (mode $20, which is 100% okay -- banks $80-FF get mirrored through bank $00-7D, with $7E/7F lost because of WRAM), and ROMSPEED_200NS (not ROMSPEED_120NS, which I think you'd need to fix).

Other nitpicks:

1. Use of rep #$38, rather than cld/rep #$30. This is another example of ridiculous optimisation for little gain -- you save 1 byte and 2 cycles at the expensive of confusing a newbie. 98% of code out there is going to use rep/sep with $10/$20/$30 and nothing else. We've already seen evidence of this being confusing for Espozo, so clearing of d of P through rep rather than just doing cld is silly, IMO.

2. I thought you and thefox said that it was possible to get the address of a MEMORY or SEGMENTS label within code itself? If that's the case, then the STACK_BASE/STACK_SIZE/LAST_STACK_ADDR and ZEROPAGE_BASE stuff shouldn't exist -- you should just be able to use whatever magic there is to do the equivalent of (pseudo code coming up) ldx #(.SEGMENT(STACK)+.sizeof(.SEGMENT(STACK))-1)/txs, and lda #.SEGMENT(DIRECTPAGE)/tcd.

3. The register equates should end up in a separate file if at all possible, and as mentioned before (again your call), use the official SNES label designation. (No I don't like the names of some of them, but consistency is good)

So now onto the formatting, and some of the above integrated:

Code:
; Make sure these conform to the linker script (e.g. lorom256.cfg).
ZEROPAGE_BASE   = $0000
STACK_BASE      = $0100
STACK_SIZE      = $0100
LAST_STACK_ADDR = STACK_BASE + STACK_SIZE - 1

PPU_BASE        = $2100
CPUIO_BASE      = $4200

.segment "CODE"
.proc resetstub
  sei                 ; turn off IRQs
  clc
  xce                 ; turn off 6502 emulation mode
  cld                 ; disable decimal mode
  jml reset_fastrom
.endproc


.segment "CODE7"
.proc reset_fastrom
  rep #$30               ; A=16, X/Y=16
  ldx #LAST_STACK_ADDR
  txs                    ; set the stack pointer

  ; Initialize the CPU I/O registers to predictable values
  lda #CPUIO_BASE
  tcd                    ; temporarily move direct page to SNES MMIO region for fast MMIO access

  ; 8< 8< 8< a bunch of stuff omitted >8 >8 >8

  lda #ZEROPAGE_BASE
  tcd                    ; return direct page to real zero page
  jml main               ; this is why I say the program bank is main >> 16
.endproc

Key things changed here:

1. Spacing of equate/= assignments. These should line up, making it visually easy for the person to know what's what. You (to date) are the only 65xx programmer I've met who doesn't "align" his formatting. Hate to single you out, but I'm being honest. Your style is your style and if I was working with you on a project and you did most of the work when I started, I'd conform to your style no matter what (that's the approach I take when collaborating), but if it was from the start I would be screaming loudly over "just two spaces then a semicolon, who cares". It really doesn't flow well.

2. Comments should be aligned as best as possible. The way I do this is the following: in the "general area" of the code, I find the longest line/instruction, then add 3 spaces, and that's where the ; for comments should "align" to throughout the surrounding code. If there are large amounts of "alignment" changes, then I tend to add an extra newline between "parts" of code, e.g. between two separate .procs, two separate .segments, etc.. You can see an example of this in resetstub vs. reset_fastrom, and the extra newline before .segment CODE7. In fact, adding some spacing (newlines) before a new .segment is very useful (to me) -- otherwise it's very easy to "forget" what segment you're working in.

3. Changed rep #$38 into rep #$30/cld, and moved the cld up to inside of resetstub. This makes it clearer what's going on within reset_fastrom. Also added comment explaining what cld does.

4. I documented what exactly rep #$30 did to A and X/Y sizes. You can ABSOLUTELY remove this comment if needed; I've gotten in the habit of doing this in the past few weeks due to Espozo, so it's a habit at this point. If I was writing my own code I wouldn't comment it.

5. Moved comment about "temporarily move direct page" to the actual tcd statement, since for your ldx #LAST_STACK_ADDR/txs example above, you had the equivalent of that type of command on the txs line, not the ldx line. I did the same for the lda #ZEROPAGE_BASE/tcd line. It's important to be consistent about your comments and where you put them.

I hope my comments (pun intended) are taken as constructive.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 9:04 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19084
Location: NE Indiana, USA (NTSC)
koitsu wrote:
ROMSPEED_200NS (not ROMSPEED_120NS, which I think you'd need to fix)

I've since moved the segments to $808000, etc.
Code:
  # The fast ROM area starts at $808000.
  # It's mirrored into the slow ROM area.
  ROM0:       start =  $808000, size = $8000, fill = yes;
  ROM1:       start =  $818000, size = $8000, fill = yes;


I've also added a snippet to the end of the init code that sets the ROM access speed as specified in the ROM header.
Code:
; in snesheader.s
.export map_mode:far
; ...
map_mode:
  .byte MAPPER_LOROM|ROMSPEED_200NS

; in init.s
MEMSEL = $80420D  ; S-CPU I/O: bit 0 enables fast ROM above $808000
; inside reset_fastrom
  lda map_mode
  and #$10
  lsr a
  lsr a
  lsr a
  lsr a
  sta MEMSEL


Quote:
I thought you and thefox said that it was possible to get the address of a MEMORY or SEGMENTS label within code itself? If that's the case, then the STACK_BASE/STACK_SIZE/LAST_STACK_ADDR and ZEROPAGE_BASE stuff shouldn't exist

Direct page I can do.
Code:
.import __ZEROPAGE_RUN__

; Mask off low byte to allow use of $000000-$00000F as local variables
ZEROPAGE_BASE = __ZEROPAGE_RUN__ & $FF00


There are two good ways to reserve space for the stack: as a constant address outside any defined MEMORY area or as the top of a .RES inside .segment "BSS". The program is currently using the former method. To use the latter, I could start BSS at $0100 and have this in init:
Code:
.segment "BSS"
stack: .res $100
stack_end:

; Then at the top of init_fastrom:
  ldx #stack_end-1
  txs

Would this be a better way?

Quote:
Spacing of equate/= assignments. These should line up, making it visually easy for the person to know what's what. You (to date) are the only 65xx programmer I've met who doesn't "align" his formatting.

Apparently other people disagree with you and prefer not lining up the equal signs in a pseudo-tabular form. See Code formatting: is lining up similar lines ok?
The justification for this is that changes to one line often require every line to be edited. That makes it more effort to change, and harder to understand diffs.


koitsu wrote:
if it was from the start I would be screaming loudly over "just two spaces then a semicolon, who cares". It really doesn't flow well.

I guess failure to horizontally align comments is another habit I picked up from C and other high-level languages, where the length of a line of code varies considerably. Even in assembly language, longer expressions such as several constants OR'd together may cause a statement to exceed 24 columns, such as .byte MAPPER_LOROM|ROMSPEED_200NS. An editor can be set to make everything after an unquoted ; character pink anyway.


Top
 Profile  
 
PostPosted: Tue Feb 10, 2015 6:41 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19084
Location: NE Indiana, USA (NTSC)
Is this an improvement at all?


Attachments:
lorom-template-0.05-pre.zip [126.89 KiB]
Downloaded 54 times
Top
 Profile  
 
PostPosted: Tue Feb 10, 2015 9:14 pm 
Offline
User avatar

Joined: Sat Jul 12, 2014 3:04 pm
Posts: 936
Quote:
The justification for this is that changes to one line often require every line to be edited. That makes it more effort to change, and harder to understand diffs.
However, in a tutorial, accessibility ideally trumps all, including creator time. And you probably aren't going to be altering line width THAT much.

Should the programming practices discussion get its own threadsplit? I still think rolled loops are more readable.

koitsu wrote:
3. Changed rep #$38 into rep #$30/cld, and moved the cld up to inside of resetstub. This makes it clearer what's going on within reset_fastrom. Also added comment explaining what cld does.
I'd use REP #$38 and point out the equivalence in a comment, were I writing it.


Top
 Profile  
 
PostPosted: Fri Feb 13, 2015 4:03 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19084
Location: NE Indiana, USA (NTSC)
I've released version 0.05 incorporating improvements based on the suggestions made by koitsu and Espozo.


Top
 Profile  
 
PostPosted: Thu Nov 17, 2016 7:52 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19084
Location: NE Indiana, USA (NTSC)
And what was going to be 0.06 until Haunted: Halloween '85 and The Curse of Possum Hollow happened is now on Git:
pinobatch/lorom-template.

Image
Git gud


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 58 posts ]  Go to page Previous  1, 2, 3, 4

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 9 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group