Initial (manual) import
This commit is contained in:
1 parent
f39611c506
commit
895fe109de
661 files changed
+245862
No files matched your search
@@ -0,0 +1,89 @@
|
||||
$WW,1$$FG,5$$TX+CX,"64-Bit Assembly Quiz"$$FG$
|
||||
|
||||
1) In 64-bit mode, how many bytes are always pushed?
|
||||
|
||||
PUSH 12
|
||||
PUSH EAX
|
||||
|
||||
2) What happens to the upper 32-bits?
|
||||
|
||||
XOR EAX,EAX
|
||||
MOV EAX,0x12345678
|
||||
MOV EAX,0x80000000
|
||||
|
||||
3) How do you set FS or GS values?
|
||||
|
||||
4) If FS points to current task record, what's wrong with this instruction?
|
||||
|
||||
MOV RAX,U64 FS:[TSS_SOME_MEMBER]
|
||||
|
||||
5) Which instruction takes more bytes?
|
||||
|
||||
MOV RAX,U64 [R8]
|
||||
MOV RAX,U64 [R13]
|
||||
|
||||
6) Are these the same number of bytes?
|
||||
|
||||
MOV RAX,1234
|
||||
MOV R8,1234
|
||||
MOV EAX,1234
|
||||
|
||||
7) True or False
|
||||
|
||||
a) You can access the lowest byte of RAX.
|
||||
|
||||
b) You can access the lowest byte of ESI.
|
||||
|
||||
c) You can access the second-to-lowest byte of RAX.
|
||||
|
||||
d) You can access the second-to-lowest byte of ESI.
|
||||
|
||||
8) How do you call a subroutine at 0x10,0000,0000 from code at 0x00,0010,0000?
|
||||
|
||||
9) How much faster is a REL32 call instruction compared to a software interrupt or SYSCALL?
|
||||
|
||||
10) How long does an IN or OUT instruction take on a 1GHz machine and on a 3GHz machine?
|
||||
|
||||
11) How do you push all 16 regs?
|
||||
|
||||
12) Should you put the regs in a TSS?
|
||||
|
||||
13) You can have 4K or 4Meg pages in 32-bit mode. You can have 4K or what size pages in 64-bit mode?
|
||||
|
||||
14) On a fresh CPU with an empty TLB, how many memory accesses (page tables) does it take to access one virtual address?
|
||||
|
||||
----
|
||||
|
||||
TempleOS identity-maps everything, all the time, so the usual convention of upper memory being for kernel does not apply. It uses physical addresses, basically. It puts all code in the lowest 2-Gig memory range so that it can use the CALL REL32 instruction, the fastest. It never changes privilege levels or messes with page tables, once it is up-and-running.
|
||||
|
||||
----
|
||||
|
||||
ANSWERS:
|
||||
|
||||
1) All stack pushes and pops are 64-bits.
|
||||
|
||||
2) The upper 32-bits are set to zero.
|
||||
|
||||
3) To set FS or GS, you use WRMSR to write a model specific reg. See $LK,"IA32_FS_BASE",A="MN:IA32_FS_BASE"$ and $LK,"SET_FS_BASE",A="MN:SET_FS_BASE"$.
|
||||
|
||||
4) Displacement addressing is now RIP relative, so RIP would be added to TSS_SOME_MEMBER. (Useless)
|
||||
|
||||
5) The R13 instruction takes one more byte because it is like $LK,"REG_RBP",A="MN:REG_RBP"$ in the ModR.
|
||||
|
||||
6) The R8 instruction needs a REX byte prefix to specify upper-8 reg.
|
||||
|
||||
7) You can access the lowest byte of any reg. You can access AH but not the second-to-lowest byte of ESI.
|
||||
|
||||
8) To call a subroutine farther than 2Gig away, you put the address into RAX, then CALL RAX.
|
||||
|
||||
9) CALL REL32 is significantly faster. See $LK,"::/Demo/Lectures/InterruptDemo.HC"$.
|
||||
|
||||
10) IN or OUT instructions happen at a fixed speed based on the original ISA bus clock.
|
||||
|
||||
11) PUSHAD is not available for 64-bit mode, so you do it by hand.
|
||||
|
||||
12) The TSS is no longer used to hold the task state because there are 16 regs and they are 64-bits, not 32-bits. I guess Intel decided doing it by hand was better than TSSes.
|
||||
|
||||
13) 64-bit mode has 4K or 2Meg page size.
|
||||
|
||||
14) For one access, there are 3-4 levels of page tables plus the location itself.
|
||||
@@ -0,0 +1,44 @@
|
||||
//$WW,1$You may wonder why I use "&" instead of "%".
|
||||
|
||||
#define SAMPLE_SIZE 100000000
|
||||
|
||||
U0 TimeIns()
|
||||
{
|
||||
I64 start1,end1,start2,end2,overhead_time,test_time;
|
||||
I64 reg i,reg tmp;
|
||||
|
||||
CPURep;
|
||||
|
||||
//Measure Loop Overhead
|
||||
start1=GetTSC;
|
||||
for (i=0;i<SAMPLE_SIZE;i++) {
|
||||
}
|
||||
end1=GetTSC;
|
||||
overhead_time=end1-start1;
|
||||
|
||||
//Measure remainder...
|
||||
start2=GetTSC;
|
||||
for (i=0;i<SAMPLE_SIZE;i++)
|
||||
tmp=i%0x400;
|
||||
end2=GetTSC;
|
||||
test_time=end2-start2;
|
||||
"Remainder Version #1 Cycles\t: %10.5f\n",
|
||||
ToF64(test_time-overhead_time)/SAMPLE_SIZE;
|
||||
|
||||
//Measure remainder...
|
||||
start2=GetTSC;
|
||||
for (i=0;i<SAMPLE_SIZE;i++)
|
||||
tmp=i&0x3FF;
|
||||
end2=GetTSC;
|
||||
test_time=end2-start2;
|
||||
"Remainder Version #2 Cycles\t: %10.5f\n",
|
||||
ToF64(test_time-overhead_time)/SAMPLE_SIZE;
|
||||
}
|
||||
|
||||
TimeIns;
|
||||
|
||||
/* Program Output$HL,0$$WW+H,1$$FD,1$
|
||||
8 Cores 2.660GHz
|
||||
Remainder Version #1 Cycles : 26.85345
|
||||
Remainder Version #2 Cycles : -0.00800
|
||||
$HL,1$*/
|
||||
@@ -0,0 +1,96 @@
|
||||
/*"Fixed point" means you use ints
|
||||
that are scaled by a value. A common
|
||||
example would be using number of pennies
|
||||
instead of dollars with a float.
|
||||
|
||||
Fixed-point used to be much $TX,"faster",HTML="http://en.wikipedia.org/wiki/X87"$,
|
||||
but modern processors do well with
|
||||
floats. It also depends on the compiler
|
||||
and my compiler is poor with floats.
|
||||
|
||||
I often use 64-bit ints with upper 32-bits
|
||||
as int and lower 32-bits as fraction.
|
||||
|
||||
See $LK,"::/Demo/SubIntAccess.HC"$ for how
|
||||
to access upper or lower 32-bits.
|
||||
|
||||
For a complete lst of nonstandard compiler
|
||||
features, see $LK,"::/Doc/HolyC.DD"$.
|
||||
*/
|
||||
|
||||
U0 Main()
|
||||
{
|
||||
F64 t0,f_sum=0,f_val;
|
||||
I64 i ,i_sum=0,i_val;
|
||||
|
||||
i_val= 2.0000002 *0x100000000;
|
||||
t0=tS;
|
||||
for (i=1000000000;i;i--)
|
||||
i_sum+=i_val;
|
||||
"Int Sum\t\t:%.9f Time:%7.3fs\n",i_sum/ToF64(0x100000000),tS-t0;
|
||||
|
||||
f_val= 2.0000002;
|
||||
t0=tS;
|
||||
for (i=1000000000;i;i--)
|
||||
f_sum+=f_val;
|
||||
"Float Sum\t:%.9f Time:%7.3fs\n",f_sum,tS-t0;
|
||||
'\n';
|
||||
}
|
||||
|
||||
U0 DoIt2()
|
||||
{
|
||||
I64 i=0x123456789ABCDEF0;
|
||||
"i\t\t=%X\n",i;
|
||||
|
||||
"i&0xFFFFFFFF\t=%X\n",i&0xFFFFFFFF;
|
||||
"i>>32\t\t=%X\n",i>>32;
|
||||
|
||||
/* Standard int types are declared
|
||||
with a special compiler feature which
|
||||
allows a structure to be accessed as a
|
||||
whole. That's why the i variable can
|
||||
be accessed normally in addition to
|
||||
structure member access $LK,"I64",A="MN:I64"$. The actual
|
||||
intrinsic compiler type is U64i.
|
||||
|
||||
public U64i union I64
|
||||
{
|
||||
I8i i8[8];
|
||||
U8i u8[8];
|
||||
I16 i16[4];
|
||||
U16 u16[4];
|
||||
I32 i32[2];
|
||||
U32 u32[2];
|
||||
};
|
||||
|
||||
It's not quite as great as it seems
|
||||
because the compiler decides it cannot
|
||||
place i into a reg, so there is a
|
||||
penalty.
|
||||
|
||||
For a complete lst of nonstandard compiler
|
||||
features, see $LK,"::/Doc/HolyC.DD"$.
|
||||
*/
|
||||
|
||||
"i.u32[0]\t=%X\n",i.u32[0];
|
||||
"i.u32[1]\t=%X\n",i.u32[1];
|
||||
}
|
||||
|
||||
CPURep;
|
||||
Main;
|
||||
DoIt2;
|
||||
|
||||
//See $LK,"::/Demo/Lectures/FixedPointAdvanced.HC"$
|
||||
|
||||
/*Program Output$HL,0$$WW+H,1$$FD,1$
|
||||
|
||||
$FG$$BG$16 Cores 3.500GHz
|
||||
Int Sum :2000000199.768690240 Time: 0.803s
|
||||
Float Sum :2000000225.656127040 Time: 3.615s
|
||||
|
||||
i =123456789ABCDEF0
|
||||
i&0xFFFFFFFF =9ABCDEF0
|
||||
i>>32 =12345678
|
||||
i.u32[0] =9ABCDEF0
|
||||
i.u32[1] =12345678
|
||||
$HL,1$*/
|
||||
@@ -0,0 +1,173 @@
|
||||
/*"Fixed point" means you use ints
|
||||
that are scaled by a value. A common
|
||||
example would be using number of pennies
|
||||
instead of dollars with a float.
|
||||
|
||||
Fixed-point used to be much $TX,"faster",HTML="http://en.wikipedia.org/wiki/X87"$,
|
||||
but modern processors do well with
|
||||
floats. It also depends on the compiler
|
||||
and my compiler is poor with floats.
|
||||
|
||||
I often use 64-bit ints with upper 32-bits
|
||||
as int and lower 32-bits as fraction.
|
||||
|
||||
See $LK,"::/Demo/SubIntAccess.HC"$ for how
|
||||
to access upper or lower 32-bits.
|
||||
*/
|
||||
|
||||
#define SAMPLE_SIZE 10000000
|
||||
|
||||
I32 coordinates[65536];
|
||||
|
||||
asm {
|
||||
_ASM_FIXED_POINT::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RSI,coordinates
|
||||
MOV RDI,ToI64(Sin(1.0)*0x100000000)
|
||||
XOR RBX,RBX //SUM
|
||||
MOV RCX,SAMPLE_SIZE-1
|
||||
@@05: XOR RDX,RDX
|
||||
MOV DX,CX
|
||||
MOVSXD RAX,U32 [RSI+RDX*4]
|
||||
IMUL RDI
|
||||
SAR RAX,32
|
||||
ADD RBX,RAX
|
||||
DEC RCX
|
||||
JGE @@05
|
||||
MOV RAX,RBX
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET
|
||||
|
||||
SINE_VAL: DU64 Sin(1.0);
|
||||
RET_VAL: DU64 0;
|
||||
|
||||
_ASM_FLOAT::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
MOV RSI,coordinates
|
||||
FLD U64 [SINE_VAL]
|
||||
FLDZ
|
||||
MOV RCX,SAMPLE_SIZE-1
|
||||
@@05: XOR RDX,RDX
|
||||
MOV DX,CX
|
||||
FILD U32 [RSI+RDX*4]
|
||||
FMUL ST0,ST2
|
||||
FADDP ST1,ST0
|
||||
DEC RCX
|
||||
JGE @@05
|
||||
FISTP U64 [RET_VAL]
|
||||
MOV RAX,U64 [RET_VAL]
|
||||
FFREE ST0
|
||||
FINCSTP
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET
|
||||
}
|
||||
|
||||
_extern _ASM_FIXED_POINT I64 AsmFixedPt();
|
||||
_extern _ASM_FLOAT I64 AsmFloat();
|
||||
|
||||
U0 Main()
|
||||
{
|
||||
I64 start,end,overhead_time,test_time;
|
||||
F64 d1,fsum;
|
||||
I64 reg i,tmp,reg d2,reg sum;
|
||||
|
||||
CPURep;
|
||||
|
||||
//Set-up some sample coordinates
|
||||
for (i=0;i<65536;i++)
|
||||
coordinates[i]=RandU32;
|
||||
|
||||
//Measure Loop Overhead
|
||||
start=GetTSC;
|
||||
for (i=SAMPLE_SIZE-1;i>=0;i--) {
|
||||
}
|
||||
end=GetTSC;
|
||||
overhead_time=end-start;
|
||||
"$$RED$$Overhead Cycles :%10.5f$$FG$$\n",
|
||||
ToF64(overhead_time)/SAMPLE_SIZE;
|
||||
|
||||
//Measure F64 arithmetic
|
||||
// (Some of this is due to crappy
|
||||
// compiler code.)
|
||||
d1=Sin(1.0);
|
||||
fsum=0;
|
||||
start=GetTSC;
|
||||
for (i=SAMPLE_SIZE-1;i>=0;i--)
|
||||
fsum+=d1*coordinates[i&65535];
|
||||
end=GetTSC;
|
||||
test_time=end-start;
|
||||
"Float Sum :%X\n",ToI64(fsum);
|
||||
"$$RED$$Float Cycles :%10.5f$$FG$$\n",
|
||||
ToF64(test_time)/SAMPLE_SIZE;
|
||||
|
||||
//Measure fixed point arithmetic
|
||||
d2=Sin(1.0)*0x100000000;
|
||||
sum=0;
|
||||
start=GetTSC;
|
||||
for (i=SAMPLE_SIZE-1;i>=0;i--) {
|
||||
tmp=d2*coordinates[i&65535];
|
||||
sum+=tmp.i32[1];
|
||||
}
|
||||
end=GetTSC;
|
||||
test_time=end-start;
|
||||
"Fixed-Point Sum :%X\n",sum;
|
||||
"$$RED$$Fixed-Point Cycles :%10.5f$$FG$$\n",
|
||||
ToF64(test_time)/SAMPLE_SIZE;
|
||||
|
||||
//Measure fixed point arithmetic
|
||||
start=GetTSC;
|
||||
sum=AsmFixedPt;
|
||||
end=GetTSC;
|
||||
test_time=end-start;
|
||||
"Asm Fixed-Point Sum :%X\n",sum;
|
||||
"$$RED$$Asm Fixed-Point Cycles:%10.5f$$FG$$\n",
|
||||
ToF64(test_time)/SAMPLE_SIZE;
|
||||
|
||||
//Measure float arithmetic
|
||||
start=GetTSC;
|
||||
sum=AsmFloat;
|
||||
end=GetTSC;
|
||||
test_time=end-start;
|
||||
"Asm Float Sum :%X\n",sum;
|
||||
"$$RED$$Asm Float Cycles :%10.5f$$FG$$\n",
|
||||
ToF64(test_time)/SAMPLE_SIZE;
|
||||
|
||||
}
|
||||
|
||||
Main;
|
||||
|
||||
/* Program Output$HL,0$$WW+H,1$$FD,1$
|
||||
|
||||
Machine 1:
|
||||
8 Cores 2.660GHz
|
||||
$FG,4$Overhead Cycles : 2.00814$FG$
|
||||
Float Sum :FFFFE1D361BEED68
|
||||
$FG,4$Float Cycles : 10.16076$FG$
|
||||
Fixed-Point Sum :FFFFE1D361729914
|
||||
$FG,4$Fixed-Point Cycles : 5.29392$FG$
|
||||
Asm Fixed-Point Sum :FFFFE1D361729914
|
||||
$FG,4$Asm Fixed-Point Cycles: 4.20464$FG$
|
||||
Asm Float Sum :FFFFE1D361BEED56
|
||||
$FG,4$Asm Float Cycles : 3.04635$FG$
|
||||
|
||||
Machine 2:
|
||||
8 Cores 3.395GHz
|
||||
$FG,4$Overhead Cycles : 4.87040$FG$
|
||||
Float Sum :D20A01DB177
|
||||
$FG,4$Float Cycles : 10.11558$FG$
|
||||
Fixed-Point Sum :D209FD18CC7
|
||||
$FG,4$Fixed-Point Cycles : 4.50618$FG$
|
||||
Asm Fixed-Point Sum :D209FD18CC7
|
||||
$FG,4$Asm Fixed-Point Cycles: 3.02426$FG$
|
||||
Asm Float Sum :D20A01DB17B
|
||||
$FG,4$Asm Float Cycles : 3.21070$FG$
|
||||
|
||||
$HL,1$*/
|
||||
@@ -0,0 +1,34 @@
|
||||
//This is the fastest you can update the whole scrn.
|
||||
//See $LK,"::/Demo/Lectures/MiniGrLib.HC"$ if this interests you.
|
||||
|
||||
F64 VGAPattern(I64 p)
|
||||
{//This returns the time to update in seconds.
|
||||
F64 start=tS;
|
||||
I64 plane;
|
||||
for (plane=1;plane<0x10;plane<<=1) {
|
||||
OutU8(VGAP_IDX,VGAR_MAP_MASK);
|
||||
OutU8(VGAP_DATA,plane);
|
||||
MemSetI64(text.vga_alias,p,640*480/64);
|
||||
}
|
||||
return tS-start;
|
||||
}
|
||||
|
||||
|
||||
U0 GrDemo()
|
||||
{
|
||||
I64 i;
|
||||
F64 t;
|
||||
CPURep;
|
||||
for (i=0;i<16;i++) {
|
||||
t=VGAPattern(0x5555555555555555);
|
||||
"$$GREEN$$Rate:$$RED$$%5.1f FPS$$FG$$"
|
||||
" $$GREEN$$Load@30Hz:$$RED$$%5.1f%%$$FG$$\n",1/t,100*t*30.0;
|
||||
t=VGAPattern(0x3333333333333333);
|
||||
"$$GREEN$$Rate:$$RED$$%5.1f FPS$$FG$$"
|
||||
" $$GREEN$$Load@30Hz:$$RED$$%5.1f%%$$FG$$\n",1/t,100*t*30.0;
|
||||
}
|
||||
//<CTRL-ALT-v> will flush scrn VGA cache.
|
||||
VGAFlush;
|
||||
}
|
||||
|
||||
GrDemo;
|
||||
@@ -0,0 +1,85 @@
|
||||
//This is the software interrupt num
|
||||
//we will use. See $LK,"Software Int's",A="MN:I_WAKE"$ for
|
||||
//picking a num. Nums are subject to change.
|
||||
|
||||
#define I_F_UNARY_MINUS I_USER
|
||||
|
||||
asm {
|
||||
|
||||
//This changes the sign of the floating
|
||||
//point val in RAX
|
||||
F_UNARY_MINUS_INT::
|
||||
PUSH RAX
|
||||
FLD U64 [RSP]
|
||||
FCHS
|
||||
FSTP U64 [RSP]
|
||||
POP RAX
|
||||
IRET
|
||||
|
||||
//This does the same thing, but not as
|
||||
//an interrupt.
|
||||
F_UNARY_MINUS_CALL::
|
||||
PUSH RAX
|
||||
FLD U64 [RSP]
|
||||
FCHS
|
||||
FSTP U64 [RSP]
|
||||
POP RAX
|
||||
RET
|
||||
|
||||
//This invokes the interrupt version
|
||||
//with a C callable function.
|
||||
_F_UM_INT::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,SF_ARG1[RBP]
|
||||
INT I_F_UNARY_MINUS
|
||||
POP RBP
|
||||
RET1 8
|
||||
|
||||
//This invokes the call version
|
||||
//with a C callable function.
|
||||
_F_UM_CALL::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,SF_ARG1[RBP]
|
||||
CALL F_UNARY_MINUS_CALL
|
||||
POP RBP
|
||||
RET1 8
|
||||
}
|
||||
|
||||
_extern _F_UM_INT F64 UnaryMinusInt(F64 d);
|
||||
_extern _F_UM_CALL F64 UnaryMinusCall(F64 d);
|
||||
|
||||
#define SAMPLE_SIZE 1000000
|
||||
U0 TimeIns()
|
||||
{
|
||||
I64 start,end;
|
||||
I64 i,old_irq;
|
||||
|
||||
CPURep;
|
||||
old_irq=IntEntrySet(I_F_UNARY_MINUS,F_UNARY_MINUS_INT,IDTET_TRAP);
|
||||
|
||||
//Measure interrupt time
|
||||
start=GetTSC;
|
||||
for (i=0;i<SAMPLE_SIZE;i++)
|
||||
UnaryMinusInt(ã);
|
||||
end=GetTSC;
|
||||
"Interrupt Cycles: %10.5f\n",ToF64(end-start)/SAMPLE_SIZE;
|
||||
|
||||
//Measure call time
|
||||
start=GetTSC;
|
||||
for (i=0;i<SAMPLE_SIZE;i++)
|
||||
UnaryMinusCall(ã);
|
||||
end=GetTSC;
|
||||
"Call Cycles: %10.5f\n",ToF64(end-start)/SAMPLE_SIZE;
|
||||
|
||||
IntEntrySet(I_F_UNARY_MINUS,old_irq,IDTET_IRQ);
|
||||
}
|
||||
|
||||
TimeIns;
|
||||
|
||||
/* Program Output$HL,0$$WW+H,1$$FD,1$
|
||||
$PT$$FG$$BG$6 Cores 3.395GHz
|
||||
Interrupt Cycles: 573.98543
|
||||
Call Cycles: 9.74349
|
||||
$HL,1$*/
|
||||
@@ -0,0 +1,236 @@
|
||||
/*$WW,1$
|
||||
$TR-C,"Main Compiler"$
|
||||
$ID,2$The mini compiler is like the main compiler, except the main compiler's lexical analyser removes comments and does preprocessing. $LK,"Lex",A="MN:Lex"$(),$LK,"Echo",A="MN:Echo"$(ON).
|
||||
|
||||
The main compiler generates $LK,"Intermediate Code",A="FF:::/Compiler/CompilerA.HH,IC_END"$ at the parser stage. See $LK,"PrsExpression",A="MN:PrsExpression"$(), $LK,"PrsStmt",A="MN:PrsStmt"$().
|
||||
|
||||
The main compiler optimizes See $LK,"Intermediate Code Attributes",A="MN:intermediate_code_table"$, $LK,"Combining Consts",A="FF:::/Compiler/OptPass012.HC,case IC_MUL"$, $LK,"Choosing Reg Vars",A="FF:::/Compiler/OptPass3.HC,cmp.num_reg_vars"$. Use $LK,"PassTrace",A="MN:PassTrace"$() to see the optimization stages.
|
||||
|
||||
The main compiler makes machine code in the back end. See $LK,"IC Struct",A="MN:CIntermediateCode"$, $LK,"COCCompile",A="MN:COCCompile"$ and $LK,"OptPass789A",A="FF:::/Compiler/OptPass789A.HC,IC_MUL"$(), $LK,"BackEnd",A="FF:::/Compiler/BackA.HC,ICMul"$. Set $LK,"Trace",A="MN:Trace"$(ON) to see the output of the backend.
|
||||
$ID,-2$
|
||||
$TR-C,"Mini Compiler"$
|
||||
$ID,2$For this mini compiler, some things you should know about 64-bit asm:
|
||||
|
||||
* Putting a 0x48, known as the REX byte, in front of an inst makes it 64-bit size.
|
||||
|
||||
* "PUSH EAX", "POP EAX" and "XOR EAX,EAX" will behave as 64-bit even without REX because the stk is always 64 bit and because the XOR clears the upper 32-bits.
|
||||
|
||||
It is okay in TempleOS to change RAX, RBX, RCX, RDX, R8 and R9 without restoring them to their original values.
|
||||
$ID,-2$$WW,0$*/
|
||||
|
||||
#define TK_EOF 0
|
||||
#define TK_NUM 1
|
||||
#define TK_OP 2
|
||||
#define TK_LEFT 3
|
||||
#define TK_RIGHT 4
|
||||
|
||||
#define OP_MUL 1
|
||||
#define OP_DIV 2
|
||||
#define OP_ADD 3
|
||||
#define OP_SUB 4
|
||||
|
||||
I64 Lex(U8 **_src,I64 *num)
|
||||
{//See $LK,"Lex",A="MN:Lex"$().
|
||||
U8 *src=*_src;
|
||||
I64 i;
|
||||
while (TRUE) {
|
||||
switch (*src) {
|
||||
case 0:
|
||||
case ';':
|
||||
*_src=src;
|
||||
return TK_EOF;
|
||||
case CH_SPACE:
|
||||
case '\r':
|
||||
case '\n':
|
||||
src++;
|
||||
break;
|
||||
case '0'...'9':
|
||||
i=0;
|
||||
do {
|
||||
i=i*10+*src-'0';
|
||||
src++;
|
||||
} while ('0'<=*src<='9');
|
||||
*num=i;
|
||||
*_src=src;
|
||||
return TK_NUM;
|
||||
case '*':
|
||||
*num=OP_MUL;
|
||||
*_src=src+1;
|
||||
return TK_OP;
|
||||
case '/':
|
||||
*num=OP_DIV;
|
||||
*_src=src+1;
|
||||
return TK_OP;
|
||||
case '+':
|
||||
*num=OP_ADD;
|
||||
*_src=src+1;
|
||||
return TK_OP;
|
||||
case '-':
|
||||
*num=OP_SUB;
|
||||
*_src=src+1;
|
||||
return TK_OP;
|
||||
case '(':
|
||||
*_src=src+1;
|
||||
return TK_LEFT;
|
||||
case ')':
|
||||
*_src=src+1;
|
||||
return TK_RIGHT;
|
||||
default:
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define PREC_EOF 0
|
||||
#define PREC_TERM 1
|
||||
#define PREC_MUL 2
|
||||
#define PREC_ADD 3
|
||||
#define PREC_PAREN 4
|
||||
|
||||
extern I64 Parse(U8 **_src,U8 **_dst);
|
||||
|
||||
U0 PrsTerm(U8 **_src,U8 **_dst,I64 prec)
|
||||
{//See $LK,"PrsExpression",A="MN:PrsExpression"$().
|
||||
I64 i;
|
||||
U8 *src2;
|
||||
U8 *dst2;
|
||||
if (Parse(_src,_dst)==PREC_TERM) {
|
||||
src2=*_src;
|
||||
dst2=*_dst;
|
||||
while (TRUE) {
|
||||
//This is inefficient. The main compiler doesn't back-up like this.
|
||||
i=Parse(&src2,&dst2);
|
||||
if (PREC_MUL<=i<prec) {
|
||||
*_src=src2;
|
||||
*_dst=dst2;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
} else
|
||||
throw;
|
||||
}
|
||||
|
||||
I64 Parse(U8 **_src,U8 **_dst)
|
||||
{//See $LK,"PrsExpression",A="MN:PrsExpression"$().
|
||||
//See $LK,"Opcode Fmts",A="FF:::/Compiler/OpCodes.DD,IDIV"$ for details on asm insts.
|
||||
I64 i;
|
||||
U8 *dst=*_dst;
|
||||
switch (Lex(_src,&i)) {
|
||||
case TK_EOF:
|
||||
*dst++=0x58; //POP RAX
|
||||
*dst++=0xC3; //RET
|
||||
*_dst=dst;
|
||||
return PREC_EOF;
|
||||
case TK_NUM:
|
||||
*dst++=0x48; //REX
|
||||
*dst++=0xB8; //MOV RAX,immediate num
|
||||
*dst(I64 *)++=i;
|
||||
|
||||
*dst++=0x50; //PUSH RAX
|
||||
*_dst=dst;
|
||||
return PREC_TERM;
|
||||
case TK_LEFT:
|
||||
PrsTerm(_src,_dst,PREC_PAREN);
|
||||
if (Parse(_src,_dst)!=PREC_PAREN)
|
||||
throw;
|
||||
return PREC_TERM;
|
||||
case TK_RIGHT:
|
||||
return PREC_PAREN;
|
||||
case TK_OP:
|
||||
switch (i) {
|
||||
case OP_MUL:
|
||||
PrsTerm(_src,&dst,PREC_MUL);
|
||||
*dst++=0x5A; //POP RDX
|
||||
*dst++=0x58; //POP RAX
|
||||
|
||||
*dst++=0x48; //REX
|
||||
*dst++=0x0F;
|
||||
*dst++=0xAF; //IMUL RAX,RDX
|
||||
*dst++=0xC2;
|
||||
|
||||
*dst++=0x50; //PUSH RAX
|
||||
*_dst=dst;
|
||||
return PREC_MUL;
|
||||
case OP_DIV:
|
||||
PrsTerm(_src,&dst,PREC_MUL);
|
||||
*dst++=0x5B; //POP RBX
|
||||
*dst++=0x58; //POP RAX
|
||||
|
||||
*dst++=0x33; //XOR RDX,RDX
|
||||
*dst++=0xD2;
|
||||
|
||||
*dst++=0x48; //REX
|
||||
*dst++=0xF7; //IDIV RBX
|
||||
*dst++=0xFB;
|
||||
|
||||
*dst++=0x50; //PUSH RAX
|
||||
*_dst=dst;
|
||||
return PREC_MUL;
|
||||
case OP_ADD:
|
||||
PrsTerm(_src,&dst,PREC_ADD);
|
||||
*dst++=0x5A; //POP RDX
|
||||
*dst++=0x58; //POP RAX
|
||||
|
||||
*dst++=0x48; //REX
|
||||
*dst++=0x03; //ADD RAX,RDX
|
||||
*dst++=0xC2;
|
||||
|
||||
*dst++=0x50; //PUSH RAX
|
||||
*_dst=dst;
|
||||
return PREC_ADD;
|
||||
case OP_SUB:
|
||||
PrsTerm(_src,&dst,PREC_ADD);
|
||||
*dst++=0x5A; //POP RDX
|
||||
*dst++=0x58; //POP RAX
|
||||
|
||||
*dst++=0x48; //REX
|
||||
*dst++=0x2B; //SUB RAX,RDX
|
||||
*dst++=0xC2;
|
||||
|
||||
*dst++=0x50; //PUSH RAX
|
||||
*_dst=dst;
|
||||
return PREC_ADD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 Main()
|
||||
{
|
||||
U8 *src,*src2,*code,*dst;
|
||||
|
||||
//Fixed size, no buffer overrun check.
|
||||
//You can make it fancier if you like.
|
||||
code=MAlloc(512,Fs->code_heap);
|
||||
|
||||
while (TRUE) {
|
||||
"This will compile an expression\n"
|
||||
"consisting of ints, parentheses\n"
|
||||
"and the operators +,-,* and /.\n";
|
||||
src=GetStr;
|
||||
if (*src) {
|
||||
src2=src;
|
||||
dst=code;
|
||||
try {
|
||||
PrsTerm(&src2,&dst,PREC_PAREN);
|
||||
if (Parse(&src2,&dst)!=PREC_EOF)
|
||||
throw;
|
||||
"$$RED$$This code is not efficient, but the compiler is simple.$$FG$$\n";
|
||||
Un(code,dst-code); //Unassemble the code we created.
|
||||
//$LK,"Call",A="MN:Call"$() is a function. See $LK,"_CALL",A="FF:::/Kernel/KUtils.HC,_CALL"$::
|
||||
//See also $LK,"CallInd",A="MN:CallInd"$(). See $LK,"_CALL_IND",A="FF:::/Kernel/KUtils.HC,_CALL_IND"$::
|
||||
"$$LTBLUE$$Answer:%d$$FG$$\n",Call(code);
|
||||
} catch {
|
||||
"$$RED$$Error$$FG$$\n";
|
||||
PutExcept;
|
||||
}
|
||||
Free(src);
|
||||
} else {
|
||||
Free(src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Free(code);
|
||||
}
|
||||
|
||||
Main;
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
//See $LK,"::/Demo/Lectures/GraphicsCPULoad.HC"$
|
||||
U8 rev[256], //The VGA bits are bwd
|
||||
|
||||
image[640*480/8]; //We need read-modify write.
|
||||
//0xA0000 alias memory can't be read.
|
||||
|
||||
U0 MGInit()
|
||||
{
|
||||
I64 i,j;
|
||||
MemSet(image,0,sizeof(image));
|
||||
MemSet(rev,0,sizeof(rev));
|
||||
for (i=0;i<256;i++)
|
||||
for (j=0;j<8;j++)
|
||||
if (Bt(&i,j))
|
||||
Bts(&rev[i],7-j);
|
||||
}
|
||||
|
||||
U0 MGUpdate()
|
||||
{//Copy image to VGA memory
|
||||
//For better performance we could only write what's changed.
|
||||
//0xA0000 alias is slower than normal RAM.
|
||||
OutU8(VGAP_IDX,VGAR_MAP_MASK);
|
||||
OutU8(VGAP_DATA,0xF);//All color planes at once -- Black and White
|
||||
MemCpy(text.vga_alias,image,sizeof(image)); //Alias of 0xA0000
|
||||
}
|
||||
|
||||
U0 MGPlot(I64 x,I64 y)
|
||||
{
|
||||
if (0<=x<640 && 0<=y<480)
|
||||
Bts(image,y*640+x^7);
|
||||
}
|
||||
|
||||
U0 MGHLine(I64 x1,I64 x2,I64 y)
|
||||
{//Warning! No clipping
|
||||
//For performance, we do as many whole-bytes as possible.
|
||||
U8 *ptr;
|
||||
I64 i,w,leading,trailing,whole_bytes;
|
||||
if (x2<x1) SwapI64(&x1,&x2);
|
||||
ptr=image+y*640/8+x1>>3;
|
||||
w=x2-x1+1;
|
||||
leading =8-x1&7;
|
||||
trailing=(x2+1)&7;
|
||||
if (leading+trailing>w)
|
||||
*ptr|=rev[(0xFF00>>leading&(0x00FF<<trailing)>>8)];
|
||||
else {
|
||||
whole_bytes=(w-leading-trailing)>>3;
|
||||
if (leading)
|
||||
*ptr++|=rev[(0xFF00>>leading)&0xFF];
|
||||
for (i=0;i<whole_bytes;i++)
|
||||
*ptr++=0xFF;
|
||||
if (trailing)
|
||||
*ptr++|=rev[(0x00FF<<trailing)>>8];
|
||||
}
|
||||
}
|
||||
|
||||
U0 MGLine(I64 x1,I64 y1,I64 x2,I64 y2)
|
||||
{//Warning! No clipping
|
||||
I64 dx=x2-x1,dy=y2-y1;
|
||||
x1<<=32; x2<<=32;
|
||||
y1<<=32; y2<<=32;
|
||||
if (AbsI64(dx)>AbsI64(dy)) {
|
||||
dy=dy<<32/AbsI64(dx);
|
||||
dx=SignI64(dx)<<32;
|
||||
while (x1!=x2) {
|
||||
MGPlot(x1.i32[1],y1.i32[1]);
|
||||
x1+=dx; y1+=dy;
|
||||
}
|
||||
} else {
|
||||
dx=dx<<32/AbsI64(dy);
|
||||
dy=SignI64(dy)<<32;
|
||||
while (y1!=y2) {
|
||||
MGPlot(x1.i32[1],y1.i32[1]);
|
||||
x1+=dx; y1+=dy;
|
||||
}
|
||||
}
|
||||
MGPlot(x1.i32[1],y1.i32[1]);
|
||||
}
|
||||
|
||||
U0 MGCircle(I64 x,I64 y,F64 r)
|
||||
{
|
||||
F64 s,c,x1,y1,x2,y2;
|
||||
I64 len;
|
||||
if (r<0) return;
|
||||
x1=r; y1=0;
|
||||
c=Cos(1/r);
|
||||
s=Sin(1/r);
|
||||
len=2*r*ã;
|
||||
MGPlot(x+x1,y+y1);
|
||||
while (len-->=0) {
|
||||
|
||||
//m1@a1 * m2@a2 = m1*m2@(arg1+arg2)
|
||||
|
||||
//(x1+y1i)*(x2+y2i) = x1*x2+(x1*y1+x2*y2)i-y1*y2
|
||||
|
||||
// me$SY,-3$ti$SY,0$=mCos(t)+imSin(t)
|
||||
|
||||
x2=x1; y2=y1;
|
||||
x1=c*x2-s*y2;
|
||||
y1=s*x2+c*y2;
|
||||
MGPlot(x+x1,y+y1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
U0 MiniGrLibDemo()
|
||||
{
|
||||
I64 i;
|
||||
MGInit;
|
||||
|
||||
for (i=0;i<100;i++)
|
||||
MGHLine(200+i,400+i,300+i);
|
||||
for (i=0;i<500;i+=10)
|
||||
MGLine(i,0,0,480-i);
|
||||
for (i=0;i<300;i+=4)
|
||||
MGCircle(200,100+i,i);
|
||||
MGUpdate;
|
||||
Busy(1500000);
|
||||
/*
|
||||
We are returning graphics to normal operations under TempleOS.
|
||||
It is not normal to by-pass the TempleOS graphcis routines.
|
||||
The TempleOS graphics don't know VGA has changed.
|
||||
This bit tells TempleOS to update whole scrn.
|
||||
*/
|
||||
//<CTRL-ALT-v> will flush scrn VGA cache.
|
||||
VGAFlush;
|
||||
}
|
||||
|
||||
MiniGrLibDemo;
|
||||
|
||||
//See $LK,"RawPutChar",A="MN:RawPutChar"$() for text.
|
||||
//See $LK,"::/Demo/Lectures/ScrnMemory.HC"$ for color.
|
||||
//See $LK,"::/Demo/Lectures/GraphicsCPULoad.HC"$.
|
||||
@@ -0,0 +1,56 @@
|
||||
class Person
|
||||
{
|
||||
U8 first [32];
|
||||
U8 last [32];
|
||||
U8 address1 [64];
|
||||
U8 address2 [64];
|
||||
U8 city [32];
|
||||
U8 state_zip[32];
|
||||
};
|
||||
|
||||
U0 OffsetDemo1()
|
||||
{
|
||||
Person *p=MAlloc(sizeof(Person));
|
||||
StrCpy(p->first, "Terry");
|
||||
StrCpy(p->last, "Davis");
|
||||
StrCpy(p->address1, "8144 Sickle Lane");
|
||||
StrCpy(p->address2, "");
|
||||
StrCpy(p->city, "Las Vegas");
|
||||
StrCpy(p->state_zip,"NV 89128");
|
||||
}
|
||||
|
||||
U(&OffsetDemo1,34);
|
||||
PressAKey;
|
||||
|
||||
/*
|
||||
|
||||
x86 has signed 8-bit displacements
|
||||
and signed 32-bit displacements.
|
||||
|
||||
This example uses 8-bit negative displacements.
|
||||
|
||||
*/
|
||||
|
||||
class Person
|
||||
{ $$=-128;
|
||||
U8 first [32];
|
||||
U8 last [32];
|
||||
U8 address1 [64];
|
||||
U8 address2 [64];
|
||||
U8 city [32];
|
||||
U8 state_zip[32];
|
||||
};
|
||||
|
||||
U0 OffsetDemo2()
|
||||
{
|
||||
Person *p=MAlloc(sizeof(Person))(I64)+128;
|
||||
StrCpy(p->first, "Terry");
|
||||
StrCpy(p->last, "Davis");
|
||||
StrCpy(p->address1, "8144 Sickle Lane");
|
||||
StrCpy(p->address2, "");
|
||||
StrCpy(p->city, "Las Vegas");
|
||||
StrCpy(p->state_zip,"NV 89128");
|
||||
}
|
||||
|
||||
U(&OffsetDemo2,34);
|
||||
PressAKey;
|
||||
@@ -0,0 +1,108 @@
|
||||
/*The moral of this story is simple
|
||||
inst level optimizations
|
||||
don't matter much on a modern Intel CPU
|
||||
because they convert complex insts
|
||||
to a stream of RISC insts.
|
||||
|
||||
I learned this the hard way when I thought
|
||||
I was greatly improving my compiler by
|
||||
cutting code by a third. No significant
|
||||
speed-up. Depressing.
|
||||
*/
|
||||
|
||||
#define SAMPLES (8*10000000+1)
|
||||
|
||||
asm {
|
||||
|
||||
LIMIT:: DU64 SAMPLES; //Memory reference should be bad, right?
|
||||
|
||||
_BADLY_UNOPTIMIZED::
|
||||
MOV RAX,0
|
||||
MOV RCX,1
|
||||
@@05: MOV RDX,RCX
|
||||
INC RCX //if no dependencies, Free!
|
||||
ADD RAX,RDX
|
||||
MOV RDX,LIMIT-16 //added 16 displacement to make it worse
|
||||
CMP RCX,U64 16[RDX]
|
||||
JB @@05
|
||||
RET
|
||||
|
||||
_WELL_OPTIMIZED1::
|
||||
XOR RAX,RAX
|
||||
MOV RCX,SAMPLES-1
|
||||
@@05: ADD RAX,RCX
|
||||
DEC RCX
|
||||
JNZ @@05
|
||||
RET
|
||||
|
||||
_WELL_OPTIMIZED2:: //Unrolled
|
||||
XOR RAX,RAX
|
||||
MOV RCX,SAMPLES-1
|
||||
@@05: ADD RAX,RCX
|
||||
DEC RCX
|
||||
ADD RAX,RCX
|
||||
DEC RCX
|
||||
ADD RAX,RCX
|
||||
DEC RCX
|
||||
ADD RAX,RCX
|
||||
DEC RCX
|
||||
ADD RAX,RCX
|
||||
DEC RCX
|
||||
ADD RAX,RCX
|
||||
DEC RCX
|
||||
ADD RAX,RCX
|
||||
DEC RCX
|
||||
ADD RAX,RCX
|
||||
DEC RCX
|
||||
JNZ @@05
|
||||
RET
|
||||
|
||||
_WELL_OPTIMIZED3::
|
||||
XOR RAX,RAX
|
||||
MOV RCX,SAMPLES-1
|
||||
@@05: ADD RAX,RCX
|
||||
LOOP @@05 //Inst has slow speed, but saves code size.
|
||||
RET
|
||||
}
|
||||
|
||||
_extern _BADLY_UNOPTIMIZED I64 Loop1();
|
||||
_extern _WELL_OPTIMIZED1 I64 Loop2();
|
||||
_extern _WELL_OPTIMIZED2 I64 Loop3();
|
||||
_extern _WELL_OPTIMIZED3 I64 Loop4();
|
||||
|
||||
I64 i;
|
||||
F64 t0;
|
||||
|
||||
CPURep;
|
||||
|
||||
"Bad Code\n";
|
||||
t0=tS;
|
||||
i=Loop1;
|
||||
"Res:%d Time:%9.6f\n",i,tS-t0;
|
||||
|
||||
"Good Code #1\n";
|
||||
t0=tS;
|
||||
i=Loop2;
|
||||
"Res:%d Time:%9.6f\n",i,tS-t0;
|
||||
|
||||
"Good Code #2\n";
|
||||
t0=tS;
|
||||
i=Loop3;
|
||||
"Res:%d Time:%9.6f\n",i,tS-t0;
|
||||
|
||||
"Good Code #3\n";
|
||||
t0=tS;
|
||||
i=Loop4;
|
||||
"Res:%d Time:%9.6f\n",i,tS-t0;
|
||||
|
||||
/* Program Output$HL,0$$WW+H,1$$FD,1$
|
||||
8 Cores 2.660GHz
|
||||
Bad Code
|
||||
Res:3200000040000000 Time: 0.069966
|
||||
Good Code #1
|
||||
Res:3200000040000000 Time: 0.062567
|
||||
Good Code #2
|
||||
Res:3200000040000000 Time: 0.062907
|
||||
Good Code #3
|
||||
Res:3200000040000000 Time: 0.156359
|
||||
$HL,1$*/
|
||||
@@ -0,0 +1,73 @@
|
||||
//See $LK,"PCI",A="HI:PCI"$.
|
||||
|
||||
#if mp_cnt>1
|
||||
#define DEST_CPU 1
|
||||
#else
|
||||
#define DEST_CPU 0
|
||||
#endif
|
||||
|
||||
#assert I_USER==0x40
|
||||
|
||||
interrupt U0 IntMy40()
|
||||
{
|
||||
lock {progress1++;}
|
||||
*(dev.uncached_alias+LAPIC_EOI)(U32 *)=0;
|
||||
}
|
||||
|
||||
interrupt U0 IntMy41()
|
||||
{
|
||||
lock {progress2++;}
|
||||
*(dev.uncached_alias+LAPIC_EOI)(U32 *)=0;
|
||||
}
|
||||
|
||||
interrupt U0 IntMy42()
|
||||
{
|
||||
lock {progress3++;}
|
||||
*(dev.uncached_alias+LAPIC_EOI)(U32 *)=0;
|
||||
}
|
||||
|
||||
interrupt U0 IntMy43()
|
||||
{
|
||||
lock {progress4++;}
|
||||
*(dev.uncached_alias+LAPIC_EOI)(U32 *)=0;
|
||||
}
|
||||
|
||||
I64 vect[4]={&IntMy40,&IntMy41,&IntMy42,&IntMy43};
|
||||
|
||||
U0 Main()
|
||||
{
|
||||
I64 i;
|
||||
U8 *da=dev.uncached_alias+IOAPIC_REG;
|
||||
U32 *_d=dev.uncached_alias+IOAPIC_DATA;
|
||||
|
||||
ProgressBarsRst;
|
||||
for (i=I_USER;i<I_USER+4;i++)
|
||||
IntEntrySet(i,vect[i&3],IDTET_IRQ);
|
||||
|
||||
//There are like 4*6 vects. Bus zero
|
||||
//has the first four vects.
|
||||
for (i=IOREDTAB;i<IOREDTAB+4*2;i+=2) {
|
||||
*da=i+1;
|
||||
*_d=dev.mp_apic_ids[DEST_CPU]<<24;
|
||||
*da=i;
|
||||
*_d=0x4000+0x40+(i-IOREDTAB)/2;
|
||||
}
|
||||
|
||||
Sleep(1000);
|
||||
"The keyboard and timer seem to be active.\n"
|
||||
"IntA:%d IntB:%d IntC:%d IntD:%d\n\n"
|
||||
"IntB is my keybaord and regs a single KEY-UP.\n"
|
||||
"Rerun and press a few keys.\n",
|
||||
progress1,progress2,progress3,progress4;
|
||||
|
||||
//Disable vects
|
||||
for (i=IOREDTAB;i<IOREDTAB+4*2;i+=2) {
|
||||
*da=i+1;
|
||||
*_d=dev.mp_apic_ids[DEST_CPU]<<24;
|
||||
*da=i;
|
||||
*_d=0x14000+0x40+(i-IOREDTAB)/2;
|
||||
}
|
||||
ProgressBarsRst;
|
||||
}
|
||||
|
||||
Main;
|
||||
@@ -0,0 +1,75 @@
|
||||
/*TempleOS runs exclusively in ring 0.
|
||||
Ring 0 is part of the $LK,"Charter",A="FI:::/Doc/Charter.DD"$.
|
||||
This demo is for you to play around
|
||||
with ring 3. TempleOS is for
|
||||
recreational programming, after all.
|
||||
|
||||
This redirects the general protection
|
||||
fault, switches to ring 3, and generates
|
||||
a fault to switch back.
|
||||
*/
|
||||
|
||||
U8 *old_stk,*new_rip;
|
||||
|
||||
asm {
|
||||
INT_TO_RING0:: //Set to handle general protection 0xD fault temporarily.
|
||||
INC U64 [SYS_PROGRESS1]
|
||||
PUSH U32 CGDT.ds //STKSEG
|
||||
MOV RAX,U64 [&old_stk]
|
||||
PUSH RAX
|
||||
PUSH U32 0 //FLAGS--interrupts off
|
||||
PUSH U32 CGDT.cs64
|
||||
MOV RAX,U64 [&new_rip]
|
||||
PUSH RAX
|
||||
IRET
|
||||
}
|
||||
|
||||
U0 Ring3Demo()
|
||||
{
|
||||
U8 *old_vect;
|
||||
"Progress1 Before:%X\n",progress1;
|
||||
CLI
|
||||
old_vect=IntEntrySet(0x0D,INT_TO_RING0,IDTET_TRAP,0);
|
||||
|
||||
TSSBusy(Gs->tss->tr_ring3,OFF);
|
||||
SetRAX(Gs->tss->tr_ring3+3);
|
||||
LTR AX
|
||||
|
||||
asm {
|
||||
MOV U64 [&old_stk],RSP
|
||||
|
||||
LEA RAX,[R3_CALLBACK]
|
||||
MOV U64 [&new_rip],RAX
|
||||
|
||||
MOV AX,CGDT.ds_ring3+3
|
||||
MOV DS,AX
|
||||
MOV ES,AX
|
||||
|
||||
PUSH U32 CGDT.ds_ring3+3 //STKSEG
|
||||
PUSH U64 [&old_stk]
|
||||
PUSH U32 0 //FLAGS--interrupts off
|
||||
PUSH U32 CGDT.cs64_ring3+3
|
||||
LEA RAX,[R3_START]
|
||||
PUSH RAX
|
||||
IRET
|
||||
|
||||
R3_START:
|
||||
INC U64 [SYS_PROGRESS1]
|
||||
CLI //This causes general protection fault #13
|
||||
|
||||
R3_CALLBACK:
|
||||
MOV AX,CGDT.ds
|
||||
MOV DS,AX
|
||||
MOV ES,AX
|
||||
}
|
||||
|
||||
TSSBusy(Gs->tss->tr,OFF);
|
||||
SetRAX(Gs->tss->tr);
|
||||
LTR AX
|
||||
|
||||
IntEntrySet(0x0D,old_vect,IDTET_IRQ,0);
|
||||
STI
|
||||
"Progress1 After :%X\n",progress1;
|
||||
}
|
||||
|
||||
Ring3Demo;
|
||||
@@ -0,0 +1,49 @@
|
||||
//This just shows how scrn memory works.
|
||||
//See $LK,"::/Demo/Lectures/MiniGrLib.HC"$
|
||||
|
||||
U0 PlotXY(I64 x,I64 y)
|
||||
{
|
||||
//Scrn bits are revd
|
||||
LBts(text.vga_alias,y*GR_WIDTH+x^7);
|
||||
}
|
||||
|
||||
U0 Main()
|
||||
{
|
||||
I64 i;
|
||||
//This makes all 4 color planes active.
|
||||
OutU8(VGAP_IDX,VGAR_MAP_MASK);
|
||||
OutU8(VGAP_DATA,WHITE);
|
||||
MemSet(text.vga_alias,0,GR_WIDTH*GR_HEIGHT/8);
|
||||
|
||||
OutU8(VGAP_IDX,VGAR_MAP_MASK);
|
||||
OutU8(VGAP_DATA,RED);
|
||||
for (i=0;i<200;i++)
|
||||
PlotXY(i,i);
|
||||
|
||||
OutU8(VGAP_IDX,VGAR_MAP_MASK);
|
||||
OutU8(VGAP_DATA,GREEN);
|
||||
for (i=0;i<200;i++)
|
||||
PlotXY(100,i);
|
||||
|
||||
OutU8(VGAP_IDX,VGAR_MAP_MASK);
|
||||
OutU8(VGAP_DATA,BLUE);
|
||||
for (i=0;i<200;i++)
|
||||
PlotXY(200-i,i);
|
||||
/*If you want a mixed color sel multiple planes
|
||||
but you have to be sure the unseled planes
|
||||
are zero, so sel them and make them zero.
|
||||
You can't do reads on VGA memory, by the way.
|
||||
That means no read-modify-writes, too.
|
||||
*/
|
||||
Busy(4000000);
|
||||
|
||||
//TempleOS has a 4 plane memory duplicate of the scrn, $LK,"gr.scrn_image",A="MN:CGrGlbls"$,
|
||||
//and only writes actual changes. See $LK,"GrUpdateVGAGraphics",A="MN:GrUpdateVGAGraphics"$().
|
||||
//<CTRL-ALT-v> will flush scrn VGA cache.
|
||||
VGAFlush;
|
||||
}
|
||||
|
||||
Main;
|
||||
|
||||
//See $LK,"::/Demo/Lectures/GraphicsCPULoad.HC"$.
|
||||
|
||||
Reference in new issue
Block a user