6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 7:38 pm

All times are UTC




Post new topic Reply to topic  [ 14 posts ] 
Author Message
PostPosted: Mon Aug 25, 2014 4:29 pm 
Offline
User avatar

Joined: Tue Mar 05, 2013 4:31 am
Posts: 1385
All, I've been working part-time on getting a simple BIOS working which will support some basic functions with a 6551 and 6522. It's quite small but also very flexible and extensible using page $03 for vector data and config data. It also provides a JMP table with 40 entries (16 used by BIOS) located at $FF00. It fits neatly into the top 1024 bytes which also includes the I/O page at ($FE00), so only 768 bytes are used, which includes 120 bytes for the JMP table, 64 bytes for vector / config data and another 17 bytes for a BIOS message. Note that there are extra Vector inserts available and 16 bytes of free config data.

As some folks get started on building an initial 65C02 system, this may be useful and get a head start of sorts. It's also heavily commented so should be quite easy to understand and modify as required. Note that it only runs with a 65C02 and will not run on an older 6502 base processor. It's also recommended that you use at least a 2MHz CPU as the interrupts can exceed 5000 per second. Note that I have a 65C51 running with a double-rate baud clock, so it's running at 38.4K. I've also got a system running at 10MHz with the BIOS and a Monitor program which is still a work in progress. Enjoy :D

Table data is provided for clock rates of: 2, 4, 5, 6, 8, 10, 12, 16MHz which are used for timer setup. The basic functions provided are:
;******************************************************************************
; The following 16 functions are provided by BIOS and available via the JMP
; Table as the last 16 entries from $FF48 - $FF75 as:
; $FF48 BEEP (send audible beep to console)
; $FF4B CHRIN (character input from console)
; $FF4E CHROUT (character output to console)
; $FF51 SETDLY (set delay value for milliseconds and 16-bit counter)
; $FF54 MSDELAY (execute millisecond delay 1-256 milliseconds)
; $FF57 LGDELAY (execute long delay; millisecond delay * 16-bit count)
; $FF5A XLDELAY (execute extra long delay; 8-bit count * long delay)
; $FF5D SETPORT (set VIA port A or B for input or output)
; $FF60 RDPORT (read from VIA port A or B)
; $FF63 WRPORT (write to VIA port A or B)
; $FF66 INITVEC (initialize soft vectors at $0300 from ROM $FDC0)
; $FF69 INITCFG (initialize soft config values at $0320 from ROM $FDE0)
; $FF6C INITCON (initialize 6551 console 19.2K, 8-N-1 RTS/CTS)
; $FF6F INITVIA (initialize 6522 default port, timers and interrupts)
; $FF72 MONWARM (warm start Monitor - jumps to page $03)
; $FF75 MONCOLD (cold start Monitor - jumps to page $03)
;******************************************************************************

Attachment:
C02BIOS.asm [34.43 KiB]
Downloaded 216 times

_________________
Regards, KM
https://github.com/floobydust


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 26, 2014 5:40 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
floobydust wrote:
All, I've been working part-time on getting a simple BIOS...

Just for grins, I loaded it into the Kowalski simulator to assemble it and look at its footprint. The assembly failed due to some label names that start with numerals. Does your assembler allow such a thing?

Quote:
$FF48 BEEP (send audible beep to console)

Wouldn't writing a <BEL> character to the console do the same thing?

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 26, 2014 1:01 pm 
Offline
User avatar

Joined: Tue Mar 05, 2013 4:31 am
Posts: 1385
Hi BDD,

Thanks for taking a look and some time at it. I'm using the WDC tools package and yes, I use some labels that start with numerals: 6551_LOAD and 6522_LOAD.

$FF48 - that's all it does... it's two bytes (LDA #$07) in front of the CHOUT routine. It save a couple bytes when used in any other code.

There's also a few other routines that will fail on assembly without the rest of the monitor code within the BRK handler:

Code:
; The following 3 subroutines are contained in the base Monitor and S/O/S code
;   - if replaced with new code, either replace or remove these routines
;
               JSR   DECINDEX   ;Decrement index to show BRK flag byte in Register display
               JSR   PRSTAT1   ;Display contents of all preset/result memory locations
               JSR   DISLINE   ;Disassemble then display instruction at address pointed to by INDEX
;


I'd be interested in any other feedback you have of course.

_________________
Regards, KM
https://github.com/floobydust


Top
 Profile  
Reply with quote  
PostPosted: Thu Mar 05, 2015 5:23 pm 
Offline
User avatar

Joined: Tue Mar 05, 2013 4:31 am
Posts: 1385
As with most initial code drops, you find some things worth changing/updating. Such is with my mini BIOS as well. I found a couple things that would benefit from some changes:

- The EXE_MSDLY and EXE_LGDLY delay routines did not save/restore used registers when called, so the calling code had to manage that if needed.
- The 6551 IRQ service routine branches upon receiving an ASCII NUL character which is used as a BRK character to interrupt a process.

Fixing the former just makes sense and reduces the amount of code from the calling routines... fixing the latter became a requirement as I recently added a Xmodem download capability to the monitor. This allows me to transfer data from a terminal program to the 65C02 board via the active console port (no cable swapping). As the CRC bytes can calculate to include a zero byte, the 6551 handler would branch to handle it as a BRK and the transfer would halt. I've added a flag which can be set to circumvent the branch to allow a NUL character to be received into the buffer. To keep the code short and fast, the check is only handled when a NUL character is received and added 4 bytes to the code.

I've tested this pretty well and Xmodem works fine (tested with ExtraPutty and TeraTerm). The transfer flag is set to $40 for an active transfer and cleared to $00 for normal BRK trapping. I used the BIT instruction to test the flag and the BVC instruction to perform the branch.

I also had to restructure and move some of the code around to free up some bytes, but it's all commented well and all functions work as before sans the above changes. I also changed labels so none start with a numeric. The source code will assemble as is with the WDC tools download. There are a few things that require alteration however:

- Monitor Cold start vector needs to point to something real (line 679)
- Monitor Warm start vector needs to point to something real (line 680)
- In the BRK handler, there are 3 NOPs which can be replaced with a JSR to the monitor to handle register display and line disassembly (line 497)

Other than this, you can add additional entries into the JMP table and alter any configuration entries as needed.


Attachments:
C02BIOS_1.1.asm [35.62 KiB]
Downloaded 151 times

_________________
Regards, KM
https://github.com/floobydust
Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 10, 2015 1:01 pm 
Offline

Joined: Thu Apr 24, 2014 3:35 am
Posts: 10
Location: Upstate NY
Awesome work! :D

I have one feature request. Could you add a BIOS function to poll input without waiting for a character? The only input function I noticed appears to wait indefinitely for input. Most firmwares I've seen just set carry and return zero if the input buffer is empty for calls like the one I'm requesting.

-jbevren


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 10, 2015 2:41 pm 
Offline
User avatar

Joined: Tue Mar 05, 2013 4:31 am
Posts: 1385
jbevren wrote:
Awesome work! :D

I have one feature request. Could you add a BIOS function to poll input without waiting for a character? The only input function I noticed appears to wait indefinitely for input. Most firmwares I've seen just set carry and return zero if the input buffer is empty for calls like the one I'm requesting.

-jbevren


Thanks, hope you find it useful in a project. Agreed that the function you're looking for is useful, I do the equivalent within my Xmodem download code in the monitor but that's the only place that I've used this function. I chose not to put it as an actual BIOS call however... as space is very tight and I'm trying to limit the JMP table entries to 16. For my hardware design, there's only 768 bytes available within the top 1KB. I use one page (256 bytes) for all hardware which limits the BIOS to 768 bytes as follows:

120 bytes for the JMP table
64 bytes for vector and config data
16 bytes for the BIOS init string
6 bytes for the CPU hardware vectors (NMI, RES, IRQ)

This only leaves me 562 bytes for actual code ;-)

The following could be added and will require another 7 bytes to implement along with another 3 bytes used in the JMP table.

Code:
;CHIN_NW subroutine: Checks for a character in the buffer;
; - if no, sets carry and exits with NUL in A reg
; - if yes, clears carry and character count in A reg
;
CHIN_NW   SEC   ;Set carry flag
         LDA   ICNT   ;Get character count
         BEQ   CHIN_RTS   ;Exit if none
         CLC   ;Else, clear carry and exit
CHIN_RTS   RTS   ;Return to caller


I will look at adding it for a future release however.... if I can find another seven free bytes ;-)

_________________
Regards, KM
https://github.com/floobydust


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 13, 2017 3:03 am 
Offline
User avatar

Joined: Tue Mar 05, 2013 4:31 am
Posts: 1385
It's been a while since this post. I've made quite a few changes to the BIOS and have decided to share it for anyone who's interested. The changes are mainly around using some of the specific C02 opcodes to reduce code size and removing the BELL command from the BIOS and replacing it with a character no-waiting call. Using some C02 specific opcodes freed up some code space, which allowed adding the CHRIN_NW routine and still end up with two free bytes of the 768 bytes allocated. The current version is 1.3, the current JMP table entries are below as well as the source file. Note that I use the WDC assembler for this. Hope someone finds something useful from this code.

;******************************************************************************
; The following 16 functions are provided by BIOS and available via the JMP
; Table as the last 16 entries from $FF48 - $FF75 as:
; $FF48 CHRIN_NW (character input from console, no waiting)
; $FF4B CHRIN (character input from console)
; $FF4E CHROUT (character output to console)
; $FF51 SETDLY (set delay value for milliseconds and 16-bit counter)
; $FF54 MSDELAY (execute millisecond delay 1-256 milliseconds)
; $FF57 LGDELAY (execute long delay; millisecond delay * 16-bit count)
; $FF5A XLDELAY (execute extra long delay; 8-bit count * long delay)
; $FF5D SETPORT (set VIA port A or B for input or output)
; $FF60 RDPORT (read from VIA port A or B)
; $FF63 WRPORT (write to VIA port A or B)
; $FF66 INITVEC (initialize soft vectors at $0300 from ROM page $FF)
; $FF69 INITCFG (initialize soft config values at $0320 from ROM page $FF)
; $FF6C INITCON (initialize 6551 console 19.2K, 8-N-1 RTS/CTS)
; $FF6F INITVIA (initialize 6522 default port, timers and interrupts)
; $FF72 MONWARM (warm start Monitor - jumps to page $03)
; $FF75 MONCOLD (cold start Monitor - jumps to page $03)
;******************************************************************************
Attachment:
C02BIOS_1.3.asm [36.95 KiB]
Downloaded 114 times

_________________
Regards, KM
https://github.com/floobydust


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 13, 2017 7:10 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
floobydust wrote:
Code:
;******************************************************************************
;   The following 16 functions are provided by BIOS and available via the JMP
;   Table as the last 16 entries from $FF48 - $FF75 as:
;   $FF48 CHRIN_NW (character input from console, no waiting)
;   $FF4B CHRIN (character input from console)
;   $FF4E CHROUT (character output to console)
;   $FF51 SETDLY (set delay value for milliseconds and 16-bit counter)
;   $FF54 MSDELAY (execute millisecond delay 1-256 milliseconds)
;   $FF57 LGDELAY (execute long delay; millisecond delay * 16-bit count)
;   $FF5A XLDELAY (execute extra long delay; 8-bit count * long delay)
;   $FF5D SETPORT (set VIA port A or B for input or output)
;   $FF60 RDPORT (read from VIA port A or B)
;   $FF63 WRPORT (write to VIA port A or B)
;   $FF66 INITVEC (initialize soft vectors at $0300 from ROM page $FF)
;   $FF69 INITCFG (initialize soft config values at $0320 from ROM page $FF)
;   $FF6C INITCON (initialize 6551 console 19.2K, 8-N-1 RTS/CTS)
;   $FF6F INITVIA (initialize 6522 default port, timers and interrupts)
;   $FF72 MONWARM (warm start Monitor - jumps to page $03)
;   $FF75 MONCOLD (cold start Monitor - jumps to page $03)
;******************************************************************************
Attachment:
C02BIOS_1.3.asm

Couple of comments:

  1. In almost all operating systems with which I have worked a function will set carry if there is an error condition, such as no datum waiting, and will clear carry if the function completed without error, such as returning a datum. I noted some inconsistency in your code in that regard.

  2. I see "magic numbers" sprinkled throughout your code. For example:

    Code:
             LDA $0100+4,X         ;Get Status Register (4)
             AND #$10              ;Mask for BRK bit set (2)

    I and other experienced 6502 assembly language programmers will know what we are seeing and understand what it represents. What about the novice who is reading your code to possibly gain insight into how to process an IRQ? Good programming practice would assign values such as $0100+4 to symbols so the reader has a clearer picture of what is going on. Why was the accumulator ANDed with $10? The reason isn't necessarily obvious unless the reader happens knows that the BRK bit in the stack copy of the status register is %00010000, which is $10, and that that bit has to be isolated to determine if this was a hard or soft interrupt.

  3. Your CHRIN function seems somewhat awkward, and CHRIN_W seems contrived. I'd be inclined to write a single function for getting data out of the serial input FIFO as follows:

    Code:
    ;================================================================================
    ;
    ;CHRIN: FETCH DATUM FROM SERIAL INPUT FIFO
    ;
    ;   —————————————————————————————————————————————————————————————————————
    ;   Calling syntax: jsr chrin
    ;                   bcs no_data
    ;                   sta datum
    ;
    ;   Exit registers: .A: datum (1)
    ;                   .X: entry value
    ;                   .Y: entry value
    ;                   SR: NV--DIZC
    ;                       ||  ||||
    ;                       ||  |||+———> 0: datum returned
    ;                       ||  |||      1: no datum
    ;                       ||  ||+————> undefined
    ;                       ||  ++—————> entry value
    ;                       ++—————————> undefined
    ;
    ;   Notes: 1) $00 returned if FIFO is empty.
    ;   —————————————————————————————————————————————————————————————————————

    CHRIN    SEC                   ;assume empty FIFO
             LDA ICNT              ;any data available?
             BEQ DONE              ;no
    ;
             PHX                   ;preserve
             LDX IHEAD             ;load FIFO pointer
             LDA IBUF,X            ;load datum
             INC IHEAD             ;bump FIFO pointer, but also...
             RMB #7,IHEAD          ;wrap it to FIFO boundaries
             DEC ICNT              ;one less datum in FIFO
             PLX                   ;restore
             CLC                   ;datum returned
    ;
    DONE     RTS                   ;done

       ...program continues

    The above uses the carry logic I previously described to tell the caller if a datum (not character—a datum read from the FIFO might not be a printable value in the ASCII range) was returned. That makes it real easy for the caller to interpret what happened. Also, the above code avoids the branch that your routine was taking when the FIFO pointer incremented to $80. Instead, the IHEAD pointer is incremented and then bit 7 is cleared with the RMB instruction, which forces IHEAD to always range between $00 and $7F (I used a syntax with RMB that is slightly different that the WDC assembler—the WDC assembler's syntax doesn't agree with that published by Rockwell when they added the RMB and SMB instructions to the 65C02).

    Note that I didn't push the status register (SR) and later restore it, as doing so doesn't really serve any purpose in your BIOS. You need to be able to at least manipulate carry so the caller can determine what transpired. The other SR bits are ephemeral and in several cases undefined upon entry, so why waste the clock cycles?

    The above function also shows the subroutine header I use, which sets forth how the function is to be called, what it will return, the state of the MPU upon return, etc. As your programming projects get larger and more complex it will become imperative that you carefully document your functions in this or a similar fashion. Otherwise, you may find yourself having to read your code to figure out what will happen to the registers, or what gets returned when certain conditions are present.

  4. Code:
    NMI_VECTOR   ;This is the ROM start for NMI Panic handler
          SEI        ;Disable interrupts
          STA AREG   ;Save A Reg
          STX XREG   ;Save X Reg
          STY YREG   ;Save Y Reg

    The SEI instruction isn't necessary, as the MPU automatically disables IRQs when any interrupt occurs.

————————————————————————————————
Edit: Gotta quit doing this late at night. I simplified the CHRIN routine somewhat.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Last edited by BigDumbDinosaur on Tue Jun 13, 2017 3:59 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 13, 2017 10:12 am 
Offline
User avatar

Joined: Tue Mar 05, 2013 4:31 am
Posts: 1385
Hi BDD,

Thanks for digging into the code a bit, always nice to have another set of eyes and mind looking at it. Some good feedback as always, however a few things in my defense:

1- I purposely opted for separate routines on CHRIN. The main routine waits until a character is available before returning, so there's no need to check the carry flag. As this routine is heavily used in the Monitor code, it would increase the code size by having to check the flag before attempting to process a received character. The CHRIN_NW routine was added later for convenience.

2- PHP/PLP in the character routines.... oops, a leftover from years ago, can't remember why I left them in there. I vaguely recall needing them at one point, possibly while working on the interrupt handler. Good catch, saves me 4 bytes too ;-)

3- NMI routine and SEI. This is perhaps a bit confusing, as the Eyes/Lichty Programming manual makes a couple statements that tend to be conflicting. One page 546 they state that NMI processing is basically identical to that of IRQ processing, which would lead one to think that interrupts would be disabled. Then on page 251, they specifically state that the feature of disabling interrupts does not apply to the NMI processing. Also, the WDC datasheet does mention the interrupt disable bit for IRQ, but not for NMI. I also noticed that the Vic20 and C64 NMI handlers start with a SEI instruction as well. I haven't looked into testing this however, just following the guidance (on page 251). I've scanned other reference material as well and haven't found anything specific beyond the above :?

_________________
Regards, KM
https://github.com/floobydust


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 13, 2017 4:47 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
floobydust wrote:
1- I purposely opted for separate routines on CHRIN. The main routine waits until a character is available before returning, so there's no need to check the carry flag. As this routine is heavily used in the Monitor code, it would increase the code size by having to check the flag before attempting to process a received character. The CHRIN_NW routine was added later for convenience.

In that case, you could use the CHRIN that I earlier psoted and wrap it in CHRIN_NW, viz.:

Code:
;================================================================================
;
;CHRIN_NW: WAIT FOR CONSOLE INPUT
;
;   —————————————————————————————————————————————————————————————————————
;   Calling syntax: jsr chrin_nw
;                   sta datum
;
;   Exit registers: .A: datum
;                   .X: entry value
;                   .Y: entry value
;                   SR: NV--DIZC
;                       ||  ||||
;                       ||  |||+———> 0
;                       ||  ||+————> undefined
;                       ||  ++—————> entry value
;                       ++—————————> undefined
;   —————————————————————————————————————————————————————————————————————
;
CHRIN_NW JSR CHRIN             ;get a datum
         BCS CHRIN_NW          ;nothing, try again
;
         RTS                   ;datum in .A
;

Speaking of the CHRIN function in my earlier post, I edited it to reduce its size.

Quote:
3- NMI routine and SEI. This is perhaps a bit confusing, as the Eyes/Lichty Programming manual makes a couple statements that tend to be conflicting. One page 546 they state that NMI processing is basically identical to that of IRQ processing, which would lead one to think that interrupts would be disabled. Then on page 251, they specifically state that the feature of disabling interrupts does not apply to the NMI processing.

Here's the relevant text on page 251:

    In addition to pushing the status and program counter information onto the stack, the d decimal flag in the status register is cleared (except on the 6502), returning arithmetic to binary mode. The i interrupt disable flag is set, preventing further interrupts until your interrupt-service routine resets it (it may do this as soon as it is finished saving the previous context) or the routine is exited (with an RTI return-from-interrupt instruction). Indeed, if the interrupt flag had already been set, the first interrupt would have been ignored as well.

    This last feature of disabling interrupts, however, does not apply to a second type of hardware interrupt, called the non-maskable interrupt (or NMI') for the very reason that it cannot be ignored, even if the i flag is set.
    NMI' is triggered by a separate pin on a 65x processor; its use is usually reserved for a single high priority interrupt, such as power failure detection.

I highlighted the confusing text. What the authors were trying to say is if IRQs are already disabled when the interrupt is taken, they will remain disabled following an RTI. In such a scenario, only an NMI or a software interrupt would be possible, which is what they meant.

The 65xx response when servicing an interrupt is the same regardless of the interrupt type. In the following, register symbols are:

  • PB - program bank, 65C816 only
  • PC - program counter
  • SR - status register

The sequence is as follows (IRQs are assumed to be enabled):

  1. PB is pushed (65C816).
  2. PC MSB is pushed.
  3. PC LSB is pushed.
  4. SR is pushed.
  5. The I bit is set in SR, disabling IRQs.
  6. The D bit is cleared in SR, putting the MPU into binary mode (65C02 and 65C816).
  7. PB is loaded with $00 (65C816).
  8. PC is loaded with the relevant vector.

As I said, the above applies to all interrupts, including BRK and COP (65C816). If a machine language monitor intercepts BRK you have to re-enable IRQs once the monitor has control. Otherwise, your system will be unresponsive to console input.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 13, 2017 5:02 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
On the visual6502, we see that the NMOS 6502 does set the I flag during the interrupt dispatch. I think this makes sense, both for IRQ and for NMI. In both cases, if the machine had been built otherwise, such that they could be interrupted and if that were not desirable, they'd need to execute SEI and even then there'd be a short window when SEI had not taken effect. On the other hand, as it is, if the respective ISRs were OK to take interrupts, they could execute a CLI at that time, and at that time they are clearly not time-critical.

So the machine behaviour is the most convenient, and it's not necessary to use SEI at the start of an ISR.

I think I have that straight.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 13, 2017 5:23 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
BigEd wrote:
In both cases, if the machine had been built otherwise, such that they could be interrupted and if that were not desirable, they'd need to execute SEI and even then there'd be a short window when SEI had not taken effect.

Right. The disabling of IRQs has to be atomic in nature. Otherwise, if another interrupt hit immediately before the SEI the MPU would not have a chance to save the current context before running off to service the new interrupt.

In the case of an NMI, IRQs must be blocked in order for the NMI to be the higher priority event.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 13, 2017 8:37 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
Going even further, since IRQ\ is level-sensitive (as it should be) and not edge-sensitive, the fact that the original single interrupt source is not satisfied would mean that the interrupt sequence would immediately followed by another interrupt sequence, again and again, before ever reaching SEI, and right away overrun the stack and never get into servicing the interrupt.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 13, 2017 10:47 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
GARTHWILSON wrote:
Going even further, since IRQ\ is level-sensitive (as it should be) and not edge-sensitive, the fact that the original single interrupt source is not satisfied would mean that the interrupt sequence would immediately followed by another interrupt sequence, again and again, before ever reaching SEI, and right away overrun the stack and never get into servicing the interrupt.

I believe that would be a condition analogous to what Gen. Chuck Yeager referred to as "augering in." :D

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC


Who is online

Users browsing this forum: DRG and 8 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: